I stumbled about a Cppcheck warning (an inconclusive one), that I mistakenly used &
instead of &&
:
/// @param code identifies the command. Only the lower 16 bits of are being processed
int encodeCmdState(bool finished, int code, bool errorneous)
{
return
(finished & 1) |
((code & 0xffff)<<1) |
((err & 1)<< 17);
}
I’m not sure if this code (style) reaches back into times where bool
wasn’t available in C. My first idea would be to simply strip the & 1
normalization from the bool
parts. But I want to be sure, so…
Is shifting bool
values “portable” and “safe”? Or, more generally:
Does the implicit bool
-to-int
conversation in arithmetic expressions always normalize values?
2
According to the C++ standard, §4.5 ad. 6 (On integral promotions):
A prvalue of type bool can be converted to a prvalue of type int, with
false becoming zero and true becoming one.
According to the C++ standard, §4.7 ad. 4 (On integral conversions):
If the destination type is bool, see 4.12. If the source type is bool,
the value false is converted to zero and the value true is converted
to one.
So a boolean true
is always converted to 1, and a boolean false
is always converted to 0, during integral promotion and conversion.
As an example take a look at this simple and naive example (http://ideone.com/kgxrTW):
#include <iostream>
using namespace std;
int main() {
bool a = true;
bool b = false;
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << boolalpha << "a = " << a << endl;
cout << boolalpha << "b = " << b << endl;
int c = a << 1;
int d = b << 1;
bool e = a << 1;
cout << "c = " << c << endl;
cout << "d = " << d << endl;
cout << "e = " << e << endl;
return 0;
}
The output of which will be:
a = 1
b = 0
a = true
b = false
c = 2
d = 0
e = true
2
As TommyA pointed out, it is safe, at least under normal circumstances.
But caution is necessary if you deal with unchecked assignments of bool
values (from input), for example when copying memory portions (naive IPC approaches using struct
s), I expected this to be possibly a problem. So I created this simple test case,
#include <iostream>
#include <cstring>
using namespace std;
int b2i(bool v)
{
return v << 1;
}
int main() {
bool v = true;
cout << "v = " << v << endl;
cout << "b2i(v) = " << b2i(v) << endl;
// simulating input:
memset(&v, -1, sizeof v);
cout << "b2i(v) = " << b2i(v) << endl;
return 0;
}
and tried it with some compilers. Indeed, the outputs differ.
C++14 and C++ 4.9.2:
v = 1
b2i(v) = 2
b2i(v) = 2
C++ 4.3.2 (also in Borland 0x0564):
v = 1
b2i(v) = 2
b2i(v) = 510