C中未初始化的变量

我有点困惑。 据我所知,如果你在C中声明一个int,而不是初始化它,例如: int x;

所以它的价值是不确定的。 因此,如果我们尝试使用它或应该有未定义的行为。

所以如果我在VS2010中运行以下代码它会使程序崩溃。

 int main(){ int a; printf("%d\n",a); return 0; } 

现在让我们来看看下一个代码,它不提供任何警告而且不会崩溃 (为什么?)

 void foo(int *var_handle){ // do nothing } int main(){ int a; foo(&a); printf("%d\n",a); // works, prints some big value return 0; } 

你能解释一下这种行为吗? 我们只添加了对一个什么都不做的函数的调用,但现在程序不会崩溃。

读取未初始化变量的值会导致未定义的行为。 未定义的行为意味着它可能崩溃。 这并不意味着它或它有义务崩溃。

未初始化的变量具有未指定的值 – 它只是未知它的值是什么。 所以在实践中,任何理智的实现,这种代码都可能永远不会崩溃。 有一个有效的内存地址支持变量,它有一些垃圾内容, printf()没有问题地读取它,将它解释为整数并打印它,就是这样。

使用未初始化的值不会直接导致未定义的行为。

Per C 2011(n1570 draft)6.7.9 10,具有自动存储持续时间的未初始化对象具有不确定的值。 根据3.19.2 1,不确定值是未指定的值或陷阱表示。 类似的文字出现在C 1999中。

如果对象具有陷阱表示,则可能发生未定义的行为。 但是,如果对象具有未指定的值,则如果对象具有某个确定值,则程序必须具有行为; 它只是没有指定对象具有哪个值。 该程序不允许仅因为未指定值而崩溃。

令人惊讶的是,您报告在Visual Studio 2010中显示崩溃的简单程序,因为我不希望int类型在Visual Studio 2010中有任何陷阱表示。可能是某些源文件不是您预期的编译和崩溃或者您已在Visual Studio 2010中启用了尝试跟踪未初始化对象的特殊调试function(但在使用foo的第二种情况下失败)。

我建议你从头开始重复测试,将你在这个问题中显示的代码粘贴到一个新文件中,并使用默认选项编译该新文件。

当然,Visual Studio 2010不符合C标准,甚至不符合旧的1999标准,因此不必遵守上述条款。 实际上,有关C标准的Visual Studio 2010的所有内容都是未定义的行为。

它是未定义的行为 ,意味着任何事情都可能发生。 直译任何东西。 行为尚未定义。

你可以试试这个。 我不知道它是否是严格未定义的行为,但是我想不出编译器实际上以未定义的方式运行并且仍然符合C标准的方法,至少如果foo在不同的编译单元中( 〜源文件),因为那时编译器不知道它会被允许产生未定义的行为;)。

 void foo(int *var_handle){ // do something to var_handle, or maybe nothing, who knows } int main(){ int a[1]; foo(a); printf("%d\n", a[0]); return 0; } 

编辑:进一步的想法:

我很确定使用函数来初始化未初始化的局部变量,通过给函数的局部变量提供非const指针是可以的。 因此,就编译器而言,仅获取局部变量的地址使其定义具有未定义值的变量。 编译器无法知道函数是否实际设置了值(函数可能在库中)。

但这只是解释了为什么它可以避免崩溃。 它可能仍然是,如果允许函数内联,并且什么都不做,则允许优化器移除调用,然后删除未初始化的局部变量的地址,从而使其仍处于“未定义的行为”状态。 您可以通过打开优化并从汇编输出validation来对您的编译器进行测试,调用foo进行内联(不生成代码),然后查看printf是否崩溃。

无法保证使用未初始化的变量会导致程序崩溃 – 这取决于垃圾数据恰好位于为变量分配的内存位置。