#include <iostream> using namespace std; union zt { bool b; int i; }; int main() { zt w; bool a,b; a=1; b=2; cerr<<(bool)2<<static_cast<bool>(2)<<endl; //11 cerr<<a<<b<<(a==b)<<endl; //111 w.i=2; int q=w.b; cerr<<(bool)q<<q<<w.b<<((bool)((int)w.b))<<w.i<<(w.b==a)<<endl; //122220 cerr<<((w.b==a)?'T':'F')<<endl; //F }
所以a,b和w.b都被声明为bool. a被分配1,b被分配2,并且w.b的内部表示被改变为2(使用联合).
这样,所有的a,b和w.b都是真的,但是a和w.b不会相等,所以这可能意味着宇宙被破坏(true!= true)
我知道这个问题比实际更理论(一个程序员不想改变一个bool的内部表示),但这里是问题:
这是可以吗? (这是用g 4.3.3测试的)我的意思是,编译器应该知道,在布尔比较期间,任何非零值可能意味着真实吗?
>你知道这个角落可能成为一个真正的问题的任何情况吗? (例如在从流中加载二进制数据时)
编辑:
三件事:
> bool和int有不同的大小,没关系.但是如果我使用char而不是int.或者当sizeof(bool)== sizeof(int)?
>请尽可能回答我问的两个问题.我实际上也对第二个问题的答案感兴趣,因为在我的诚实意见中,在嵌入式系统(可能是8位系统)中,这可能是一个真正的问题(或不是).
>新问题:这是真的未定义的行为吗?如果是,为什么?如果没有,为什么?在规范中的布尔比较运算符中是否没有任何假设?
解决方法
- Is this okay? (this was tested with g++ 4.3.3) I mean,should the compiler be aware that during boolean comparison any non-zero value might mean true?
非零的任何整数值(或非NULL的指针)都表示为true.
但是当比较整数和bool时,在比较之前将bool转换为int.
- Do you know any case where this corner case might become a real issue? (For example while binary loading of data from a stream)
这是一个真正的问题.
Is this okay?
I don’t know whether the specs specify anything about this. A compiler might always create a code like this: ((a!=0) && (b!=0)) || ((a==0) && (b==0)) when comparing two booleans,although this might decrease performance.
In my opinion this is not a bug,but an undefined behavIoUr. Although I think that every implementor should tell the users how boolean comparisons are made in their implementation.
如果我们去最后一个代码示例,那么a和b都是bool,并且通过分配1和2来设置为true(否则1和2消失,它们现在只是真的).
所以打破你的表情:
a!=0 // true (a converted to 1 because of auto-type conversion) b!=0 // true (b converted to 1 because of auto-type conversion) ((a!=0) && (b!=0)) => (true && true) // true ( no conversion done) a==0 // false (a converted to 1 because of auto-type conversion) b==0 // false (b converted to 1 because of auto-type conversion) ((a==0) && (b==0)) => (false && false) // false ( no conversion done) ((a!=0) && (b!=0)) || ((a==0) && (b==0)) => (true || false) => true
所以我总是期望上面的表达式得到很好的定义,并且始终是真实的.
但我不知道这是如何适用于您的原始问题.当将一个整数分配给bool时,整数将转换为bool(如上所述). true的实际表示不是由标准定义的,可以是适合bool的任何位模式(您不能假定任何特定的位模式).
当将bool与int进行比较时,将bool转换为int,然后进行比较.
Any real-world case
The only thing that pops in my mind,if someone reads binary data from a file into a struct,that have bool members. The problem might rise,if the file was made with an other program that has written 2 instead of 1 into the place of the bool (maybe because it was written in another programming language).
But this might mean bad programming practice.
以二进制格式编写数据是不可知的.
每个对象的大小都有问题.
有代表性的问题:
>整数(有endianess)
> Float(表示未定义(通常取决于底层硬件))
Bool(二进制表示法未定义)
>结构(成员之间的填充可能不同)
所有这些您需要知道底层硬件和编译器.编译器的不同编译器或不同版本的编译器,甚至具有不同优化标记的编译器可能对上述所有操作都有不同的行为.
联盟的问题
struct X { int a; bool b; };
当人们提到写“a”,然后从’b’读取是未定义的.
为什么:因为我们不知道在这个硬件上如何表示’a’或’b’.写入’a’将填写’a’中的位,但如何反映在’b’中的位.如果您的系统使用1字节布尔和4字节整数,低位存储器中的最低字节为最低字节,则将1写入’a’将1置于’b’.但那么你的实现如何代表一个bool?是真的表示1或255?如果将1置入’b’,并且真正使用255的所有其他用途会发生什么?
所以除非你了解你的硬件和你的编译器的行为将是意想不到的.
因此,这些用途是未定义的,但不被标准所禁止.他们被允许的原因是你可能已经做了这个研究,发现在你的系统上使用这个特定的编译器,你可以做一些自由的优化,做出这些假设.但是请注意,假设中的任何更改将会破坏您的代码.
另外当比较两种类型时,编译器将在比较之前进行一些自动转换,请记住在比较之前将两种类型转换为相同类型.为了在整数和bool之间进行比较,将bool转换为整数,然后与另一个整数进行比较(转换将false转换为0,并将其转换为1).如果要转换的对象都是bool,那么不需要转换,并且使用布尔逻辑进行比较.