int bar = 2;
if (bar)
{
int bar;
}
gcc 或 Clang 都无法为此发出警告(或错误),并且程序在启动时立即崩溃。这有充分的理由吗?看起来也不是什么难抓的东西。这是块作用域的基础知识:嵌套作用域继承封闭块的名称...
有什么解释吗?
编辑:事实证明崩溃是由于使用 Clang 造成的。我来回测试了很多次,似乎可以肯定是变量重定义和 Clang 的组合导致了崩溃。但是,我无法在测试项目中重现崩溃,所以请自行想象。
问题原来与 Objective-C 相关。正如 Jonathan Leffler 指出的那样,在内部作用域中执行“int bar = bar”会从自身初始化变量,这就是当通过 Objective-C 方法调用完成初始化时导致问题的原因。
以下显示了正在发生的错误:
-(void)crasher
{
NSNumber* bar = [NSNumber numberWithInt:2];
if (bar)
{
NSString* bar = [self doit:bar];
}
}
-(NSString*)doit:(NSNumber*)num
{
NSString* str = [num stringValue]; // This line causes the crash
return str;
}
请注意,在纯 C 中执行类似的操作不会产生崩溃:
int bar = 2;
if (bar)
{
char buff[10];
int bar = sprintf(buff, "%d",bar);
}
隐藏外部块中的变量。这是该语言自古以来就存在的完美标准功能。
您遇到的崩溃与您发布的代码完全无关。除非您在代码中犯了错误,否则请在假设您正在使用外部变量的同时使用内部变量。
#include <stdio.h>
static int xx(int foo)
{
int bar = 2;
if (foo > bar)
{
int foo = bar;
int bar = bar;
printf("inner: foo = %d, bar = %d\n", foo, bar);
}
printf("outer: foo = %d, bar = %d\n", foo, bar);
return bar;
}
int main(void)
{
xx(13);
return(0);
}
请注意,内部栏是从自身初始化的 - 这会产生未定义的行为。 但在 MacOS X 10.6.2 (GCC 4.2.1) 上我得到:
inner: foo = 2, bar = 0
outer: foo = 13, bar = 2
i
之前还是之后声明
a
,我都会从这段代码中获得相同的输出,并使用堆栈遍历函数。
inner: foo = 2, bar = 20
outer: foo = 13, bar = 2
代码:
#include <stdio.h>
static void modify_stack(void)
{
int a[20];
int i;
for (i = 0; i < 20; i++)
{
a[i] = 0xFFFFFFFF ^ i;
printf("a[i] = 0x%08X\n", a[i]);
}
}
static int xx(int foo)
{
int bar = 2;
if (foo > bar)
{
int foo = bar;
int bar = bar;
printf("inner: foo = %d, bar = %d\n", foo, bar);
}
printf("outer: foo = %d, bar = %d\n", foo, bar);
return bar;
}
int main(void)
{
modify_stack();
xx(13);
return(0);
}
由于行为未定义,所以这个结果很好。
变体 2:堆栈践踏 - B
#include <stdio.h>
static int modify_stack(void)
{
int a[20];
int i;
for (i = 0; i < 20; i++)
{
a[i] = 0xFFFFFFFF ^ i;
printf("a[i] = 0x%08X\n", a[i]);
}
i = a[13];
return(i);
}
static int xx(int foo)
{
int bar = 2;
if (foo > bar)
{
int foo = bar;
int bar = bar;
printf("inner: foo = %d, bar = %d\n", foo, bar);
}
printf("outer: foo = %d, bar = %d\n", foo, bar);
return bar;
}
int main(void)
{
int i = modify_stack();
xx(13);
return(i & 0xFF);
}
输出(除了循环打印的数据):
inner: foo = 2, bar = -14
outer: foo = 13, bar = 2
$ gcc 1.c
$ gcc -Wall 1.c
1.c: In function ‘main’:
1.c:6: warning: unused variable ‘bar’
$ cat 1.c
int main()
{
int bar = 2;
if (bar)
{
int bar;
}
return 0;
}
$ ./a.out ; echo $?
0
为我编译 - 在 -Wall 下有警告。并且程序运行正常。
您声明了两个变量,一个称为
bar
,另一个也称为
bar
。编译器不在乎,只要它们位于不同的作用域即可。