C++中的未初始化变量行为

22
我已经检查过了,我写了一个像这样的程序。
int main() {
 int i;
 cout << i;
 return 0;
}

我运行了几次这个程序,结果每次都是一样的——零。 我已经尝试了在C语言中运行,结果也是一样的。

但是我的教材上说:

如果你未初始化函数内定义的变量,那么变量值将保持未定义。这意味着元素将取代先前在该内存位置驻留的任何值。

当程序总是分配一个空闲内存位置给变量时,这怎么可能发生呢?它怎么可能不是零(我假设默认空闲内存值为零)?


8
这是C++和C中的未定义行为。标题中提到了C,但cout是C++中的。 - Shafik Yaghmour
由于它是未定义的,编译器“可能”(但不一定)在使用之前分配0来生成程序。 - deviantfan
那是什么教材? - Lightness Races in Orbit
1
你是如何尝试 C++ 中的 cout 的呢? - Deanie
1
@Daenie 我用了printf,但是我太懒了,没粘贴C代码。 - omidh
4个回答

24
当程序总是将一个自由内存位置分配给变量时,这怎么可能呢?它怎么可能不是零而是其他值呢?
让我们看一个实际的例子实现。
假设它利用堆栈来保留局部变量。
void
foo(void)
{
        int foo_var = 42;
}

void
bar(void)
{
        int bar_var;
        printf("%d\n", bar_var);
}

int
main(void)
{
        bar();
        foo();
        bar();
}

上面的代码完全是错误的,这说明了一个问题。在我们调用foo之后,foo_var所在的某个位置被设置为42。当我们调用bar时,bar_var占据了这个确切的位置。实际上,执行代码的结果是打印0和42,表明bar_var的值不能依赖于初始化。

现在应该清楚了,需要对局部变量进行初始化。但是,main是否可以例外呢?有没有什么东西可以玩弄堆栈,并给我们一个非零值呢?

是的。main不是程序中第一个执行的函数。事实上,需要进行大量的工作来设置一切。其中任何工作都可能使用堆栈并在其上留下一些非零值。不仅您不能期望在不同操作系统上获得相同的值,而且它甚至可能在您正在使用的系统上突然更改。感兴趣的人可以搜索“动态链接器”。

最后,C语言标准甚至没有堆栈这个术语。留下为本地变量“分配空间”的任务交给了编译器。它甚至可以从一个给定的寄存器中随意获取任何东西。实际上,如果触发未定义行为,编译器有自由做任何它想做的事情。


2
"C语言标准",C不是C++。 - Pharap
由于此示例调用未定义的行为,因此您应该提及您使用的确切编译器和编译器设置以重现观察到的行为。 - Thomas Weller

14
如果您在函数内定义了一个变量但没有初始化,那么该变量的值将保持未定义状态。这一点是正确的。但如果变量是基于内存中以前的值来计算的,则该语句就不正确了。有时实际操作中会发生这种情况,您应该意识到是否为零完全符合程序运行的任何给定运行。理论上,编译器可以随意对该整数分配一个随机初始值,因此试图对此进行合理化是完全无意义的。但让我们继续假设“元素采用先前驻留在内存位置的任何值”,那么它可能是零以外的其他值(我假设默认释放的内存值为零)。嗯,这就是假设导致的问题。 :)

此外,一些编译器可能会完全删除内存访问,这种情况下你将访问寄存器值。 - yyny

5
这段代码调用了未初始化的变量,导致产生了“未定义行为”(Undefined Behavior,UB)。
当使用警告标志,如-Wall时,编译器应该发出警告。
warning: 'i' is used uninitialized in this function [-Wuninitialized]
  cout << i;
          ^

恰巧,在您的系统上执行时,它的值为0。这意味着变量分配的垃圾值恰好是0,因为内存中的剩余部分表明如此。

然而,请注意,内核零经常出现。这意味着我可以经常在系统输出中得到零,但不能保证,并且不应该作为承诺。


2
我喜欢你提到编译器标志,比如“-Wall”。 - hyena
1
恰好你的编译器会给你一个输出任意 int 的程序,标准允许该整个程序产生任何可观察的行为。 - Caleth

3

静态变量和全局变量都被初始化为零:

Global:
int a;  //a is initialized as 0

void myfunc(){
   static int x;     // x is also initialized as 0
   printf("%d", x);}

非静态变量或自动变量,即局部变量是不确定的(通常指它可以做任何事情。它可以是零,也可以是其中的值,还可以导致程序崩溃)。在分配值之前读取它们会导致未定义的行为。

void myfunc2(){
   int x;        // value of x is assigned by compiler it can even be 0
   printf("%d", x);}

这主要取决于编译器,但通常情况下大多数编译器都会将其预设为0。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接