打印未初始化的变量时会发生什么?

问题描述 投票:0回答:4

我检查过自己,我写了一个这样的程序

int main() {
 int i;
 cout << i;
 return 0;
}

我运行了该程序几次,结果始终相同,为零。 我用C试过了,结果是一样的。

但是我的教科书说

如果没有初始化已定义的变量 在函数内部,变量值保持未定义。这意味着该元素采用 先前驻留在内存中该位置的任何值。

当程序总是为变量分配空闲内存位置时,这怎么可能?它怎么可能是零以外的值(我假设默认可用内存值为零)?

c++ initialization undefined-behavior
4个回答
25
投票

当程序总是分配空闲内存时,这怎么可能 变量的位置?它怎么可能是某个东西而不是零呢?

让我们看一个实际实现的示例。

假设它利用堆栈来保存局部变量。

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 不是程序中执行的第一个函数。事实上,设置一切都需要大量的工作。任何这项工作都可以使用堆栈并在其上留下一些非零值。您不仅不能期望在不同的操作系统上具有相同的值,而且在您现在使用的系统上它很可能会突然发生变化。有兴趣的可以google一下“动态链接器”。 最后,C语言标准甚至没有堆栈这个术语。为局部变量留出一个“位置”是留给编译器的。它甚至可以从给定寄存器中发生的任何事情中获得随机的垃圾。它真的可以是“任何东西”。事实上,如果触发了未定义的行为,编译器可以自由地做任何想做的事情。

如果不初始化函数内定义的变量,则变量值将保持未定义状态。

14
投票
这句话是真的。

这意味着该元素采用先前驻留在内存中该位置的任何值。

这一点不是。

有时在实践中会发生这种情况,您应该意识到,对于任何给定的程序运行,
获得零

未获得零

完全符合这一理论。 理论上,如果需要,您的编译器实际上可以为该整数分配一个随机初始值,因此尝试合理化这一点是完全没有意义的。但让我们继续假设“该元素采用先前驻留在内存中该位置的任何值”......

它怎么可能不是零(我假设默认可用内存值为零)?

嗯,这就是当你假设时会发生的情况。 :)

此代码调用

未定义行为

5
投票

当使用警告标志时,编译器应该发出警告,例如 -Wall

warning: 'i' is used uninitialized in this function [-Wuninitialized] cout << i; ^


碰巧,在这次运行中,在您的系统上,它的值为 0。这意味着分配给该变量的垃圾值恰好为 0,因为那里的内存剩余表明如此。

但是,请注意,
内核零出现相对频繁

。这意味着我的系统输出为零是很常见的,但它不能得到保证,也不应该被视为承诺。

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


3
投票

非静态变量或

auto
变量,即局部变量是
不确定

(不确定通常意味着它可以做任何事情。它可以是零,它可以是那里的值,它可以使程序崩溃) 。在赋值之前读取它们会导致未定义的行为。 void myfunc2(){ int x; // value of x is assigned by compiler it can even be 0 printf("%d", x);} 这主要取决于编译器,但一般情况下,编译器会将该值预先假定为 0

© www.soinside.com 2019 - 2024. All rights reserved.