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的脚注中写道:
以所述方式使用bool值 按此国际标准 “未定义”,,例如,通过检查a的值 未初始化的自动对象, 可能会导致表现得好像 既不真实也不虚假。
所以无论我编译和运行这个程序多少次,我都得到相同的输出: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
。
答案 0 :(得分:17)
我只是想知道为什么未初始化的bool的这种突然变化?
反汇编代码,看看编译器在做什么。
我的猜测:由于该值现在仅在本地使用,因此编译器会完全优化它。由于行为未定义,编译器可以安全地假设任何值,例如, false
。这是一个非常明显的优化,因为b
的值就编译器而言是恒定的,并且switch
的整个逻辑是多余的。那么为什么要把它放在可执行文件中呢?
(这里重要的一点是b
只在第二个代码中本地使用,而且即使在未经优化的代码中也会触发更多优化。第一个代码必须在编译器之前内联做任何这样的优化,或者必须跟踪代码路径,这不是微不足道的。)
答案 1 :(得分:1)
就在今天,我遇到了这个bug的一个版本。我在这里提供我的经验,以防它对任何人有启发。
我有一些代码可以归结为
if(!(a == b && c.d())) { do_something(); }
我追逐的错误是do_something()
正在发生,错误地发生。然而,a
肯定等于b
,而c.d()
似乎也是如此。
当我跟踪这个时,我暂时添加了这些测试打印输出:
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()
,它似乎是真的。”
我没有检查汇编代码,但我猜测在某些情况下,gcc正在测试它是否为非零,但在其他情况下,它只是测试低阶位。
正确初始化_successful
会让错误消失。 (由于早期的程序员首先编写了方法d()
,因此它已经未被初始化了十年。但是这个错误直到几个月前才出现。这就是为什么,有时候,软件是硬。)