奇怪的C ++布尔转换行为(true!= true) [英] Strange C++ boolean casting behaviour (true!=true)

查看:213
本文介绍了奇怪的C ++布尔转换行为(true!= true)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

只要在内部大学课程上阅读:

  #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)wb))< a)<< endl; // 122220
cerr<<((w.b == a)?'T':'F')<< // F
}

所以 a b wb 都声明为 bool 已分配 1 b $ c> 2 ,并将 wb 的内部表示更改为 2 a



b wb 将是 true ,但 a wb 不会相等,所以这可能意味着宇宙被破坏( true != true



我知道这个问题比实际问题更理论化(因为程序员不想改变 bool ),但这里有一些问题:


  1. (这是用g ++ 4.3.3测试的)我的意思是,如果编译器知道在布尔比较任何非零值可能意味着真实?

  2. Do你知道任何情况下,这个角落的情况可能成为一个真正的问题? (例如从流中加载二进制数据时)

编辑:



三件事:


  1. bool int 有不同的大小,没关系。但是如果我使用 char 而不是 int ,该怎么办?或者 sizeof(bool)== sizeof(int)


  2. 问题我问如果可能。我实际上对第二个问题的答案感兴趣,因为在我的老实说,在嵌入式系统(可能是8位系统),这可能是一个真正的问题(或不是)。


  3. 新问题:这是否真的未定义行为?如果是,为什么?如果不是,为什么?



解决方案

blockquote>


  1. 这是否正确? (这是用g ++ 4.3.3测试的)我的意思是,如果编译器知道在布尔比较任何非零值可能意味着真的?




任何非零的整数值(或非NULL指针)表示true。
但是当比较整数和bool时,bool在比较之前转换为int。



  1. 你知道这种情况可能会成为一个真正的问题吗? (例如,从流中二进制加载数据)


这是一个真正的问题。



  1. 这是否可以?



    我不知道规范是否指定任何关于这一点。编译器可能总是创建这样的代码:((a!= 0)&&(b!= 0))|| (a == 0)&&(b == 0)),虽然这可能会降低性能。



    一个bug,但是一个未定义的行为。虽然我认为每个实现者都应该告诉用户在它们的实现中如何进行布尔比较。




$ b b

如果我们去你的最后一个代码示例,a和b都是bool,并通过分配1和2设置为true(Noe 1和2消失,现在只是真的)。​​



这样分解你的表达式:

  a!= 0 // true的自动类型转换)
b!= 0 // true(由于自动类型转换,b转换为1)

((a!= 0)& = 0))=> (true&& true)// true(不执行转换)

a == 0 // false(由于自动类型转换而转换为1)
b == 0 / / false(由于自动类型转换,b转换为1)

((a == 0)&&(b == 0))=> (false& false)// false(无转换)

((a!= 0)&& ((a == 0)&&(b == 0))=> (true || false)=> true

所以我总是期望上面的表达式被明确定义,



但我不知道这如何适用于您的原始问题。当给bool赋一个整数时,整数被转换为bool(如前所述)。 true的实际表示不是由标准定义的,可以是任何适合在bool中的位模式(您不能假定任何特定的位模式)。



当比较



  1. p>任何现实情况



    如果有人从文件中读取二进制数据到结构体,并且有bool成员,那么我唯一想到的就是。如果文件是用另一个程序写成2而不是1到bool的地方(可能是因为它是用另一种编程语言编写的),那么问题可能会出现。



    但这可能意味着不好的编程习惯。



二进制格式是不可移植的,没有知识。

每个对象的大小有问题。

表示有问题:




  • 整数(有字节顺序)

  • Float(表示未定义(通常取决于底层硬件))

  • Bool(二进制表示法未被标准定义)

  • Struct(成员之间的填充可能不同)



有了所有这些,你需要知道底层的硬件和编译器。不同的编译器或不同版本的编译器,或者不同的优化标志的编译器可能有不同的行为。



Union的问题

  struct X 
{
int a;
bool b;
};

由于人们提到写'a',然后从'b'读取未定义。
为什么:因为我们不知道'a'或'b'在这个硬件上是如何表示的。写入'a'将填充'a'中的位,但是它如何反映在'b'中的位。如果你的系统在高位存储器中使用1字节的bool和4字节的int和低字节的最低字节,那么写入1到'a'将把1放在'b'。但是你的实现如何代表一个bool?真实表示为1还是255?如果你把一个'b'和所有其他使用的真正的是使用255会发生什么?



所以,除非你了解你的硬件和你的编译器的行为将是意想不到的。



因此这些用途是未定义的,但不被标准禁止。他们被允许的原因是,你可能已经做了研究,发现在你的系统与这个特定的编译器,你可以通过做这些假设做一些freeky优化。但是警告假设的任何变化都会破坏你的代码。



同样,当比较两种类型时,编译器会在比较之前做一些自动转换,记住这两种类型转换进入相同类型进行比较。对于整数和bool之间的比较,bool被转换为整数,然后与另一个整数进行比较(转换将false转换为0,true转换为1)。如果被转换的对象都是bool,则不需要转换,并且使用布尔逻辑进行比较。


Just read on an internal university thread:

#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
}

So a,b and w.b are all declared as bool. a is assigned 1, b is assigned 2, and the internal representation of w.b is changed to 2 (using a union).

This way all of a,b and w.b will be true, but a and w.b won't be equal, so this might mean that the universe is broken (true!=true)

I know this problem is more theoretical than practical (a sake programmer doesn't want to change the internal representation of a bool), but here are the questions:

  1. 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?
  2. Do you know any case where this corner case might become a real issue? (For example while loading binary data from a stream)

EDIT:

Three things:

  1. bool and int have different sizes, that's okay. But what if I use char instead of int. Or when sizeof(bool)==sizeof(int)?

  2. Please give answer to the two questions I asked if possible. I'm actually interested in answers to the second questions too, because in my honest opinion, in embedded systems (which might be 8bit systems) this might be a real problem (or not).

  3. New question: Is this really undefined behavior? If yes, why? If not, why? Aren't there any assumptions on the boolean comparison operators in the specs?

解决方案

  1. 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?

Any integer value that is non zero (or pointer that is non NULL) represents true. But when comparing integers and bool the bool is converted to int before comparison.

  1. Do you know any case where this corner case might become a real issue? (For example while binary loading of data from a stream)

It is always a real issue.

  1. 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.

If we go by your last code sample both a and b are bool and set to true by assigning 1 and 2 respectfully (Noe the 1 and 2 disappear they are now just true).

So breaking down your expression:

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

So I would always expect the above expression to be well defined and always true.

But I am not sure how this applies to your original question. When assigning an integer to a bool the integer is converted to bool (as described several times). The actual representation of true is not defined by the standard and could be any bit pattern that fits in an bool (You may not assume any particular bit pattern).

When comparing the bool to int the bool is converted into an int first then compared.

  1. 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.

Writing data in a binary format is non portable without knowledge.
There are problems with the size of each object.
There are problems with representation:

  • Integers (have endianess)
  • Float (Representation undefined ((usually depends on the underlying hardware))
  • Bool (Binary representation is undefined by the standard)
  • Struct (Padding between members may differ)

With all these you need to know the underlying hardware and the compiler. Different compilers or different versions of the compiler or even a compiler with different optimization flags may have different behaviors for all the above.

The problem with Union

struct X
{
    int  a;
    bool b;
};

As people mention writing to 'a' and then reading from 'b' is undefined.
Why: because we do not know how 'a' or 'b' is represented on this hardware. Writing to 'a' will fill out the bits in 'a' but how does that reflect on the bits in 'b'. If your system used 1 byte bool and 4 byte int with lowest byte in low memory highest byte in the high memory then writing 1 to 'a' will put 1 in 'b'. But then how does your implementation represent a bool? Is true represented by 1 or 255? What happens if you put a 1 in 'b' and for all other uses of true it is using 255?

So unless you understand both your hardware and your compiler the behavior will be unexpected.

Thus these uses are undefined but not disallowed by the standard. The reason they are allowed is that you may have done the research and found that on your system with this particular compiler you can do some freeky optimization by making these assumptions. But be warned any changes in the assumptions will break your code.

Also when comparing two types the compiler will do some auto-conversions before comparison, remember the two types are converted into the same type before comparison. For comparison between integers and bool the bool is converted into an integer and then compared against the other integer (the conversion converts false to 0 and true to 1). If the objects being converted are both bool then no conversion is required and the comparison is done using boolean logic.

这篇关于奇怪的C ++布尔转换行为(true!= true)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆