2
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);       
}
4

5 回答 5

7

这里没有什么可以捕捉的。内部块中的变量是一个完全不同的变量,它隐藏了外部块中的变量。这是从一开始就存在的语言的完美标准特征。

您遇到的崩溃与您发布的代码完全无关。除非您在代码中犯了错误,否则在假设您正在使用外部变量的同时使用内部变量。

于 2010-03-05T17:04:59.543 回答
4

它是嵌套作用域的基础:在嵌套作用域内,您可以隐藏在外部作用域中声明的内容。gcc 有一个选项来获得这个警告(-Wshadow),但它没有被 -Wall 或 -Wextra 激活:警告可以在代码中出现而无需更改(标题现在在全局范围内定义了函数中使用的标识符)。

于 2010-03-05T17:09:14.510 回答
1
$ 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。编译器不在乎,只要它们在不同的范围内。

于 2010-03-05T17:06:58.633 回答
1

这也是块作用域的基础,在内部作用域中从外部作用域重新定义名称不是错误——这是正常的和预期的。否则基本上会让我们回到只有全局变量的古代 BASIC 方言的糟糕过去。

于 2010-03-05T17:07:19.827 回答
1

扩展 Douglas Leeder 给出的答案:

#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

变体 1:堆栈践踏 - A

有趣的是,无论我声明ibefore 还是 after ,我都会从这段代码中得到相同的输出,并带有一个堆栈践踏函数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
于 2010-03-05T17:33:27.817 回答