Consider the program below.
All comparisons are true with a recent gcc but only the value 1 compares equal with the Visual Studio commandline compiler v. 19.16.27031.1 for x86.
I believe that it's generally OK to write into PODs through char pointers; but is there wording in the standard about writing funny values into bool variables? If it is allowed, is there wording about the behavior in comparisons?
#include <iostream>
using namespace std;
void f()
{
if(sizeof(bool) != 1)
{
cout << "sizeof(bool) != 1\n";
return;
}
bool b;
*(char *)&b = 1;
if(b == true) { cout << (int) *(char *)&b << " is true\n"; }
*(char *)&b = 2;
if(b == true) { cout << (int) *(char *)&b << " is true\n"; }
*(char *)&b = 3;
if(b == true) { cout << (int) *(char *)&b << " is true\n"; }
}
int main()
{
f();
}
P.S. gcc 8.3 uses a test
instruction to effectively check for non-zero while gcc 9.1 explicitly compares with 1, making only that comparison true. Perhaps this godbolt link works.
No. This is not OK.
Writting arbitrary data in a bool is much UB (see What is the strict aliasing rule?) and similar to Does the C++ standard allow for an uninitialized bool to crash a program?
*(char *)&b = 2;
This type punning hack invoke UB. According to your compiler implementation for bool
and the optimization it is allowed to do, you could have demons flying off your nose.
Consider:
bool b;
b = char{2}; // 1
(char&)b = 2; // 2
*(char*)&b = 2; // 3
Here, lines 2 and 3 have the same meaning, but 1 has a different meaning. In line 1, since the value being assigned to the bool
object is nonzero, the result is guaranteed to be true
. However, in lines 2 and 3, the object representation of the bool
object is being written to directly.
It is indeed legal to write to an object of any non-const
type through an lvalue of type char
, but:
In C++17, the standard does not specify the representation of bool
objects. The bool
type may have padding bits, and may even be larger than char
. Thus, any attempt to write directly to a bool
value in this way may yield an invalid (or "trap") object representation, which means that subsequently reading that value will yield undefined behaviour. Implementations may (but are not required by the standard to) define the representation of bool
objects.
In C++20, my understanding is that thanks to P1236R1, there are no longer any trap representations, but the representation of bool
is still not completely specified. The bool
object may still be larger than char
, so if you write to only the first byte of it, it can still contain an indeterminate value, yielding UB when accessed. If bool
is 1 byte (which is likely), then the result is unspecified---it must yield some valid value of the underlying type (which will most likely be char
or its signed or unsigned cousin) but the mapping of such values to true
and false
remains unspecified.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With