Storing 8 logical true/false values inside 1 byte?

C++Bit Fields

C++ Problem Overview


I'm working on a microcontroller with only 2KB of SRAM and desperately need to conserve some memory. Trying to work out how I can put 8 0/1 values into a single byte using a bitfield but can't quite work it out.

struct Bits
{
    int8_t b0:1, b1:1, b2:1, b3:1, b4:1, b5:1, b6:1, b7:1;
};

int main(){
	Bits b;
	b.b0 = 0;
	b.b1 = 1;

	cout << (int)b.b0; // outputs 0, correct
	cout << (int)b.b1; // outputs -1, should be outputting 1
}

What gives?

C++ Solutions


Solution 1 - C++

All of your bitfield members are signed 1-bit integers. On a two's complement system, that means they can represent only either 0 or -1. Use uint8_t if you want 0 and 1:

struct Bits
{
    uint8_t b0:1, b1:1, b2:1, b3:1, b4:1, b5:1, b6:1, b7:1;
};

Solution 2 - C++

As a word of caution - the standard doesn't really enforce an implementation scheme for bitfields. There is no guarantee that Bits will be 1 byte, and hypothetically it is entirely possible for it to be larger.

In practice however the actual implementations usually follow the obvious logic and it will "almost always" be 1 byte in size, but again, there is no requirement that it is guaranteed. Just in case you want to be sure, you could do it manually.

BTW -1 is still true but it -1 != true

Solution 3 - C++

As noted, these variables consist of only a sign bit, so the only available values are 0 and -1.

A more appropriate type for these bitfields would be bool. C++14 §9.6/4:

> If the value true or false is stored into a bit-field of type bool of any size (including a one bit bit-field), the original bool value and the value of the bit-field shall compare equal.

Yes, std::uint8_t will do the job, but you might as well use the best fit. You won't need things like the cast for std::cout << (int)b.b0;.

Solution 4 - C++

Signed and unsigned integers are the answer.

Keep in mind that signaling is just an interpretation of bits, -1 or 1 is just the 'print' serializer interpreting the "variable type", as it was "revealed" to cout functions (look operator overloading) by compiler, the bit is the same, its value also (on/off) - since you have only 1 bit.

Don't care about that, but is a good practice to be explicit, so prefer to declare your variable with unsigned, it instructs the compiler to mount a proper code when you set or get the value to a serializer like "print" (cout).

"COUT" OPERATOR OVERLOADING: "cout" works through a series of functions which the parameter overloading instructs the compiler which function to call. So, there are two functions, one receives an unsigned and another signed, thus they can interpret the same data differently, and you can change it, instructing the compiler to call another one using cast. See cout << myclass

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJazcashView Question on Stackoverflow
Solution 1 - C++Carl NorumView Answer on Stackoverflow
Solution 2 - C++dtechView Answer on Stackoverflow
Solution 3 - C++PotatoswatterView Answer on Stackoverflow
Solution 4 - C++LucianoView Answer on Stackoverflow