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

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

问题描述

刚刚看了一个内部​​大学螺纹:

 的#include<&iostream的GT;
使用命名空间std;工会ZT
{
 布尔B:
 INT I;
};诠释的main()
{
 ZT瓦;
 布尔A,B;
 一个= 1;
 B = 2;
 CERR<<(布尔)2';<的static_cast<布尔>(2)LT;< ENDL; // 11
  CERR&所述;&下;一个与所述;&所述; b将;≤(一个== 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&LT;&LT;((W.B ==一)'T':'F')LT;&LT; ENDL; //F
}

所以 A B WB 都是声明为布尔 A 分配 1 B 分配 2 ,以及内部重新$ p $ 的WB 更改为 2 (使用联盟)。

这样,所有的 A B WB 真正,但 A WB 荣获' T为相等,所以这可能意味着,宇宙被打破(真!= TRUE

我知道这个问题是理论多于实际(清酒程序员并不想改变的内部重新presentation一个布尔),但这里有问题:


  1. 这样行吗? (这与G ++ 4.3.3测试过)我的意思是,如果编译器知道,布尔比较期间的任何的非零值,可能意味着真的吗?

  2. 请您知道这个角落情况下,有可能成为一个真正的问题无论如何? (例如,而从流加载二进制数据)

编辑:

三件事情:


  1. 布尔 INT 有不同的大小,没关系。但是,如果我用字符而不是 INT 。或者当的sizeof(布尔)==的sizeof(INT)


  2. 请给予回答这两个问题,我问如果可能的话。我在回答第二个问题真正感兴趣过,因为在我的真实想法,在嵌入式系统(这可能是8位系统),这可能是一个真正的问题(或没有)。


  3. 新的问题:这是的真正的未定义行为?如果是,为什么?如果不是,为什么?不存在对规范中的布尔比较运算符?

  4. 任何假设

解决方案

  

      
  1. 这样行吗? (这与G ++ 4.3.3测试过)我的意思是,如果编译器知道,布尔比较期间的任何非零值,可能意味着真的吗?

  2.   

的任一整数值,该值是非零(或指针即非空)重新presents真。
但对比整数和BOOL当布尔转换比较前为int。


  

      
  1. 请您知道这个角落情况下,有可能成为一个真正的问题无论如何? (例如,而从流数据的二进制加载)

  2.   

它始终是一个真正的问题。


  

      
  1. 这样行吗?


      
      

    我不知道是否规范指定有关这事。编译器可能会始终创建code是这样的:(!(A = 0)及及(B = 0))|| ((A == 0)及&放大器;(二== 0))。比较两个布尔值时,虽然这可能会降低性能


      
      

    在我看来,这是不是一个错误,而是一个未定义的行为。虽然我认为每个执行者应该告诉用户如何比较布尔在执行制成。


  2.   

如果我们去你的最后code样品a和b是布尔并通过指定1和2恭敬地设置为true(诺埃1和2消失,他们现在只是真)。

所以,打破你的前pression:

  A!= 0 //真(一转换为1,因为自动类型转换)
b!= 0 //真(二转换为1,因为自动型转换)((α= 0)及!及(B = 0)!)=&GT; (真放;&安培;真)//真(无转换完成)一个== 0 //假(一转换为1,因为自动类型转换)
b == 0 //假(B转换为1,因为自动类型转换)((A == 0)及&放大器;(二== 0))=&GT; (假&安培;&安培;假)//假(无转换完成)((α= 0)及!&放大器;!(B = 0))|| ((A == 0)及&放大器;(二== 0))=&GT; (真||假)=&GT;真正

所以,我总是会想到上面的前pression得到很好的定义,总是如此。

但我不知道如何适用于你原来的问题。当分配给一个布尔整数整数转换为bool(描述几次)。真正的实际再presentation不是由标准定义,并可能适合在布尔(你可以不承担任何特定的位模式)。

的位模式

在比较布尔为int的布尔转换成一个int先进行比较。


  

      
  1. 任何真实世界的情况下


      
      

    这是持久性有机污染物在我的脑海里,如果有人读取文件的二进制数据到一个结构,有布尔成员的唯一的事。这个问题可能上升,如果文件与写2,而不是1到布尔(也许是因为它是写在另一种编程语言)的地方的其他程序进行。


      
      

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


  2.   

以二进制格式

写入数据是没有知识的非便携的。

有与每个对象的大小问题。

没有与重新presentation问题:


  • 整数(有字节序)

  • 浮动(再presentation未定义((通常取决于底层硬件上))

  • 布尔(二进制重新presentation由标准未定义)

  • 结构体(成员之间的填充可能会有所不同)

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

与联盟问题

 结构点¯x
{
    int类型的;
    布尔B:
};

随着人们提写'一',然后从'B'读书是不确定的。

为什么:因为我们不知道A或B是怎么psented在此硬件重新$ P $。写A将填补出位'A',但怎么做,在B的位反映。如果您的系统使用1个字节布尔和低内存最低位字节的高内存然后写1到'A'将投入1'B'级最高字节4字节INT。但是,您的实现重新present那么如何做一个布尔值?是真的重新$ P $ 1或255 psented?如果你把1B和真正的所有其他使用它使用255会发生什么?

所以,除非你了解双方你的硬件和你的编译器的行为将无法预料。

因此​​,这些用途是未定义的,但不是由标准不允许。他们被允许的原因是,你可能已经做了研究,发现你的系统上使用这个特定的编译器可以通过这些假设做了一些优化freeky。但要注意的假设的任何变化都会打破你的code。

也比较之前比较两种编译器会做一些自动转换时,记住这两种类型转换为同一类型比较之前。用于整数和布尔之间的比较的布尔被转换成一个整数,然后对其他整数进行比较(转换转换假至0℃,真到1)。如果被转换的对象都是布尔需要那么没有转换和比较使用布尔逻辑进行。

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 ++布尔铸造行为(真!=真)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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