3

I was thinking about microoptimizing a function that returns 4 bools by using an union of uint32_t and bool[4], and then doing the popcnt instruction to see how many elements of the bool array are true.

But I do not know if the standard guarantees that bool is represented as number with only 1 bit set when true and 0 bits set when it is false.

If the answer is no then I have a follow up question: if it is not required is it required that representation is constant, e.g. if I have a test that checks that true bool casted to uint_8t is 1(and 0 for false) does that this means that every representation of bools in the program will behave the same.

note: I know that it is not required that bool is 1byte, but I can static_assert on that.

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
NoSenseEtAl
  • 28,205
  • 28
  • 128
  • 277
  • 7
    *I was thinking about microoptimizing a function that returns 4 bools by using an union of uint32_t and bool[4], and then doing the popcnt instruction to see how many elements of the bool array are true.* Why not just use a `std::bitset`? – NathanOliver Aug 26 '19 at 13:51
  • related/dupe: https://stackoverflow.com/questions/2725044/can-i-assume-booltrue-int1-for-any-c-compiler – NathanOliver Aug 26 '19 at 13:52
  • 8
    In C++ it's not allowed to use unions for type-punning, it breaks strict aliasing. – Some programmer dude Aug 26 '19 at 13:52
  • [basic](http://eel.is/c++draft/basic) `Type bool is a distinct type that has the same object representation, value representation, and alignment requirements as an implementation-defined unsigned integer type. The values of type bool are true and false.` - I think from that it's totally implementation defined if it has 1 bit set or any (if any) number of bits set. – KamilCuk Aug 26 '19 at 14:08
  • 1
    Casting does not provide any information. The booleans convert to 1 (`true`) and 0 (`false`), but these conversions are independent of the actual representation of the booleans. – molbdnilo Aug 26 '19 at 14:21
  • @KamilCuk -- it's not implementation-defined. It's unspecified. In the standard, implementation-defined means that the implementation must specify what it does. – Pete Becker Aug 26 '19 at 15:51
  • 1
    Some compilers do exceedingly weird things with invalid `bool`s, so I wouldn't try anything clever. Take a look at the "Unitialized Scalar" and "Invalid Scalar" examples here: https://en.cppreference.com/w/cpp/language/ub – alter_igel Aug 26 '19 at 18:35

1 Answers1

9

I was thinking about microoptimizing a function that returns 4 bools by using an union of uint32_t and bool[4], and then doing the popcnt instruction to see how many elements of the bool array are true.

That will cause undefined behavior because accessing an inactive member of the union violates the object lifetime rules. You probably want to use a std::bitset<4> instead — it is designed for usage like this.

Note that std::bitset cannot directly be constructed from several bools, you may have to compose an unsigned long long first. Or you can use a helper function like this:

template <std::size_t N>
constexpr std::bitset<N> pack_bools(const bool (&arr)[N])
{
    static_assert(N <= std::numeric_limits<unsigned long long>::digits);

    unsigned long long num{0};
    for (std::size_t i = 0; i < N; ++i) {
        if (arr[i])
            num += 1LL << i;
    }
    return std::bitset<N>{num};
}

usage:

pack_bools({true, false, true, false}); // for example

(test)

But I do not know if the standard guarantees that bool is represented as number with only 1 bit set when true and 0 bits set when it is false.

No, there's no guarantee like that. [basic.fundamental]/10:

Type bool is a distinct type that has the same object representation, value representation, and alignment requirements as an implementation-defined unsigned integer type. The values of type bool are true and false. [ Note: There are no signed, unsigned, short, or long bool types or values. — end note ]

There's no more guarantee about the value representation.

If the answer is no then I have a follow up question: if it is not required is it required that representation is constant, e.g. if I have a test that checks that true bool casted to uint_8t is 1(and 0 for false) does that this means that every representation of bools in the program will behave the same.

No, there's no such guarantee either.

L. F.
  • 19,445
  • 8
  • 48
  • 82
  • I am not sure about violating object lifetime rules since both members of the union are POD, but I could be wrong since often my intuition is wrong, and stuff that is *obviously* ok to me is actually UB. – NoSenseEtAl Aug 26 '19 at 14:14
  • "There's nothing more than that." is somewhat incorrect: conversions to and from e.g. pointer types and other integer types are also defined (i.e. 0/null/nullptr converts to `false` and the rest converts to `true`). Granted, this only specifies type value conversions, not underlying representation. – rubenvb Aug 26 '19 at 14:15
  • 2
    @NoSenseEtAl POD isn't really that important when it comes to lifetime rules. And yes, sometimes what we all assume is well defined is not :) – L. F. Aug 26 '19 at 14:17
  • iirc talk about object lifetimes from cppcon by some google guy says we can use pods uninitialized, but maybe it is not guaranteed that they contain nonjunk value... but again C++ is very complicated and I do not want to argue about this since it is not the main question and I am pretty sure you are right. :) – NoSenseEtAl Aug 26 '19 at 14:19