为什么GCC / Clang在不同情况下的初始化时表现不同?

时间:2014-01-02 09:06:56

标签: c gcc clang llvm llvm-gcc

我尝试使用GCC和Clang / LLVM的以下版本的代码:

版本1

#include <stdio.h>    
main() {
    work();
    return 0;
}
work() {
    int b;
    printf("b: %d \n", b);
}

第2版

#include <stdio.h>    
main() {
    work();
    return 0;
}
work() {
    int a = 1;
    int b;
    printf("a: %d b: %d \n", a, b);
}

第3版

#include <stdio.h>    
void work() {
    int a = 1;
    int b;
    printf("a: %d b: %d \n", a, b);
}
int main(int argc, char** argv) {
    work();
    return 0;
}

对于GCC,

版本1输出b: 0

版本2输出a: 1 b: 4195728

版本3输出a: 1 b: 1742650088

对于Clang(LLVM),

版本1输出b: 0

版本2输出a: 1 b: -1643302816

版本3输出a: 1 b: 0

我多次在多台机器上运行相同的代码。产生“0”的那些 总是产生“0”,也就是说,在这些情况下,b被初始化。

问题:

  1. 是什么让GCC和Clang在版本1中始终生成“0”?

  2. 是什么让Clang在版本3中始终生成“0”?

2 个答案:

答案 0 :(得分:4)

读取一个永远不会被初始化并且从不采用地址的变量具有未定义的行为。这意味着编译器实现者可以选择任何喜欢的东西。所以如果你真的有兴趣直接询问实现者,而不是我们。但正如Pascal建议的那样,我不认为他们会对你的问题感兴趣,我也怀疑你在他们的文档中可能会发现任何有趣的东西。但由于这些是开源编译器,您可以查看源代码以了解它们正在做什么。

从本质上讲,你不能指望你的代码有任何明智之处。

如果您对编译器以及他们必须告诉您的内容感兴趣,请至少为您的代码启用一些警告(使用-Wall)。根据现代标准,你拥有的前两个版本甚至都不是C.

答案 1 :(得分:0)

您正在访问未初始化的变量b。 C ++标准没有指定读取时的值。它可以在同一编译二进制文件的不同运行中不同。这一切都取决于变量“b”所在的内存位置。编译器不会将其初始化为任何值。

事实上,我认为这是一个“未定义”的行为,完全未定义,并且编译器会格式化您的硬盘驱动器或使应用程序崩溃或崩溃操作系统,这将是一个有效的,符合标准的C ++编译器。

因此,简而言之:不要读取未初始化的变量,也不要期望在执行此操作时读取的值。