未初始化变量和编译器(GCC)的乐趣

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

C++ 标准第 §3.9.1/6 节说,

bool 类型的值为

true
false

现在考虑这段代码,

void f(bool b)
{
    switch(b) //since b is bool, it's value can be either true or false!
    {
        case true: cout << "possible value - true";  break;
        case false: cout << "possible value - false"; break;
        default: cout << "impossible value";
    }
}
int main()
{
    bool b; //note : b is uninitialized
    f(b);
    return 0;
}

编译

F:\workplace>g++ test.cpp -pedantic

跑。输出:

不可能的价值

意外的输出?嗯,事实并非如此,正如标准在 §3.9.1/6 的脚注中所述:

按照描述的方式使用布尔值 按照本国际标准 “未定义”,例如 通过检查某个值 未初始化自动对象, 可能会导致它表现得像 不真实也不虚假

因此,无论我编译并运行该程序多少次,我都会得到相同的输出:

impossible value

。但是,如果我稍微改变一下 - 从图片中删除函数 
f()
,并在 
switch
 本身中写入 
main()
 块:

int main() { bool b; //note : b is uninitialized switch(b) //since b is bool, it's value can be either true or false! { case true: cout << "possible value - true"; break; case false: cout << "possible value - false"; break; default: cout << "impossible value"; } return 0; }

然后我编译并运行这个程序,我没有得到

impossible value

 作为输出;无论我重复多少次,我都不会明白
impossible value

我只是想知道为什么未初始化 bool 的行为会突然发生变化?

嗯,从语言的角度来看,很明显:行为是未定义的。我理解这一点。我也明白编译器可以自由地做任何事情。然而,从编译器的角度来看,这对我来说似乎非常有趣。

编译器(即 GCC)在每种情况下可能会做什么?为什么?

我正在使用:

g++ (GCC) 4.5.0 - MinGW, on Windows 7 Basic, 64-bit OS

c++ gcc initialization undefined-behavior
2个回答
17
投票
我只是想知道为什么未初始化 bool 的行为会突然发生变化?

反汇编代码,看看编译器在做什么。

我的猜测:由于该值现在仅在本地使用,因此编译器将其完全优化掉。由于行为无论如何都是未定义的,编译器可以安全地假设任何值,例如

false

。这是一个非常明显的优化,因为就编译器而言,
b
的值是恒定的,并且
switch
的整个逻辑是多余的。那么为什么要把它放在可执行文件中呢?

(这里重要的一点是,

b

仅在第二个代码中本地使用,即使在未优化的代码中,这反过来也会触发更多的优化。第一个代码必须先内联,然后编译器才能进行任何此类优化,或者必须跟踪代码路径,这并不简单)。


1
投票
就在今天,我遇到了这个错误的一个版本。 我在这里提供我的经验,以防对其他人有所启发。

我有一些代码可以归结为

if(!(a == b && c.d())) { do_something(); }

我一直在追寻的 bug 是

do_something()

 错误地发生了。  然而 
a
 绝对等于 
b
 并且 
c.d()
 看起来返回 true。

当我追踪这个问题时,我临时添加了这些测试打印输出:

if( a == b && c.d() ) printf("yes\n"; else printf("no\n"); if(!(a == b && c.d())) printf("noo\n"; else printf("yess\n");

令我惊讶的是,这打印了

yes

noo
,这既证实了为什么 
do_something
 发生,也证实了正在发生一些非常奇怪的事情。

事实证明方法

d()

类似于

bool whatever::d() { return _successful; }

但是

_successful

未初始化。  当我打印出它的值时,它是 236,这就是为什么我之前说过“
c.d()
 似乎返回 true。”

我没有检查汇编代码,但我猜测在某些情况下,gcc正在测试它是否非零,但在其他情况下,它只是测试低位。

正确初始化

_successful

使错误消失。  (自从早期的程序员首次编写方法
d()以来,它已经有十年
没有初始化了。然而,直到几个月前,这个错误才显现出来。这就是为什么有时,软件很难。)

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.