GCC

时间:2015-06-15 20:54:47

标签: c gcc struct clang scoping

考虑以下C程序

#include <stdio.h>

typedef struct s {
  int x;
} s_t;

int main() {
  int x;
  s_t a;

  scanf("%d", &x);

  if (x > 0) {
    s_t a;
    a.x = x;
  }

  printf("%d\n", a.x);
}

if分支中的a struct变量清楚地隐藏了main中的a struct变量。可以预期printf中的输出将是未定义的,但是对于GCC,范围变量似乎等于主变量。

例如

gcc test.c -o test
echo 10 | ./test

将输出10.

另一方面,通过clang执行此操作,按预期执行

clang test.c -o test
echo 10 | ./test

输出-2145248048。

这是一个GCC错误还是存在某种未触发的行为?

gcc 4.8.2 clang 3.4

4 个答案:

答案 0 :(得分:9)

正如其他人所提到的,你正在阅读一个未初始化的局部变量,这是未定义的。所以,任何事都是合法的。话虽如此,这种行为有一个特殊原因:gcc尽可能多地在堆栈上重用变量(即,只要生成的代码可证明是正确的)。您可以使用-fstack-reuse选项进行微调。

禁用堆栈重用:

gcc test.c -o test -fstack-reuse=none
echo 10 | ./test
4195808 # prints some random number.

为所有变量启用堆栈重用:

gcc test.c -o test -fstack-reuse=all  #, or -fstack-reuse=named_vars
echo 10 | ./test
10 # prints 10, as it reuses the space on the stack.

这在GCC Code Generation Options完整记录。

答案 1 :(得分:4)

  

可以预期printf中的输出将是未定义的

未定义。未定义的行为意味着任何事情都可能发生,包括(但不限于)任何特定的输出。

在这种情况下,可能发生的事情是编译器优化a两个地址。

答案 2 :(得分:4)

没有编译器错误,您的程序会调用未定义的行为。

您正在读取未初始化的自动对象,C表示它具有不确定的值,并且读取它是未定义的行为。

a.x(在main范围内声明的那个)一个值,为程序指定一个特定的行为。

答案 3 :(得分:3)

  

这是一个GCC错误还是存在某种未触发的行为?

它未定义的行为。 s_t a;语句中的if隐藏了之前a的声明 在块中

if (x > 0) {
    s_t a;
    a.x = x;
}  

x已分配给本地a.x。在此阻止之后,a不再可用,并且在printf中您正在访问未初始化的变量。未初始化的变量可以调用UB。