3

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
  • Bit manipulation is much easier to reason about if you just convert everything to unsigned beforehand. Commented Jan 7, 2015 at 11:10
  • @SebastianRedl Maybe, BTW: the posted example is a simplified extract of the real code.
    – Wolf
    Commented Jan 7, 2015 at 11:56

2 Answers 2

5

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
  • I unaccepted this answer for rethinking my last experiences (there is a difference between the C++ standard and the every-day job I was referring as always)
    – Wolf
    Commented Jan 7, 2015 at 14:38
  • I finally accept this answer: The compiler is not responsible for repairing uninitialized/manipulated/corrupted memory. Although some compilers are broken for some cases of integer promotion. If in doubt, test!
    – Wolf
    Commented May 31, 2018 at 7:43
1

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 structs), 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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.