【问题标题】:Scoping rules for struct variables in GCCGCC 中结构变量的范围规则
【发布时间】:2015-06-15 20:54:46
【问题描述】:

考虑下面的 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 结构变量明显遮盖了 main 中的 a 结构变量。人们会认为 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 铿锵3.4

【问题讨论】:

  • a 在 main 处未初始化。没有意义。在 main 的顶层尝试 s_t a = {77};
  • 您可以通过 (a) 在 if 语句的范围内打印 a.x 和 (b) 在 main() 的顶级范围内初始化 a.x 来改进您的测试, (c) 在if 语句之前和之后打印a.x。这些步骤应该消除未定义的行为并使正在发生的事情更清楚。然后我们可以开始讨论您看到的内容以及是否存在错误。但是,虽然您的代码中有未定义的行为,但您无权投诉;任何事情都可能发生,这是调用未定义行为的有效结果。

标签: c gcc struct clang scoping


【解决方案1】:

正如其他人所提到的,您正在读取一个未初始化的局部变量并且它是未定义的。所以,任何事情都是合法的。话虽如此,这种行为有一个特殊的原因: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 上有完整记录。

【讨论】:

  • 有趣。您是否能够在使用中展示它,并产生不同的结果。如果是这样,那么值得添加到您的答案中。
  • 优秀;投赞成票。感谢您提供信息。
  • @hacks,添加了参考。
  • 从学术角度来看很有趣。然而,这可能会诱使一些人利用它而不是编写正确的代码。
【解决方案2】:

人们会认为 printf 中的输出是未定义的

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

在这种情况下,可能发生的情况是编译器将两个a 优化为具有相同的地址。

【讨论】:

  • 如果您检查生成的程序集(例如,通过使用 gcc 的 -S 开关),它可能会准确显示正在发生的事情
【解决方案3】:

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

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

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

【讨论】:

    【解决方案4】:

    这是 GCC 错误还是触发了某种未定义的行为?

    这是未定义的行为。 if 语句中的s_t a; 隐藏了a 的先前声明。
    在区块中

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

    x 分配给本地a.x。在此块之后,a 不再可用并且在printf 中您正在访问一个未初始化的变量。未初始化的变量可能会调用 UB。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-10-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多