1

From the cppreference

#include <iostream>
struct S {
    // will usually occupy 2 bytes:
    // 3 bits: value of b1
    // 2 bits: unused
    // 6 bits: value of b2
    // 2 bits: value of b3
    // 3 bits: unused
    unsigned char b1 : 3, : 2, b2 : 6, b3 : 2;
};
int main()
{
    std::cout << sizeof(S) << '\n'; // usually prints 2
}

Why is that 2 bits unused?

Couldn't be just:

unsigned char b1 : 3, b2 : 6, b3 : 2;

Is this a way of padding?

Could anyone explain me if (if I am not wrong) this bit fields actually change the size of the variable or they are just a "suggestion" for the compiler? (as inline keyword). If bit fields works as I understand, you would be able to stor a boolean on 1 bit (which is not possible because the memory is splitted on chunks of 1 bytes)

Cătălina Sîrbu
  • 1,253
  • 9
  • 30
  • It's just introducing the idea of unused bits and padding – Jose Jul 30 '20 at 15:32
  • Providing an unnamed field is for positioning and padding of those unused bits within the bit-structure. In C++, I much prefer making getter/setter methods, and doing the masking and shifting myself instead of using the bitfield specifiers. (Not because I "don't trust the compiler", rather because I find it more readable and maintainable.) – Eljay Jul 30 '20 at 15:33
  • bitfield is implementation specific, (some implementations for example don't split bits into different *"bit containers"* (`unsigned char` here)) (so in current example, 3bit padding would be after the unnamed `:2` and not after `b2`). – Jarod42 Jul 30 '20 at 15:34
  • No, bit fields are not a way of aligning data. Most processors can't align variable allocation to the nearest bit; usually it's 8-bit, 16-bit or 32-bit address alignment. – Thomas Matthews Jul 30 '20 at 15:44
  • Bit fields are a method of associate a variable to a bit. This becomes useful when dealing with hardware registers where bits have different meanings (such as transmission buffer empty or overrun error). – Thomas Matthews Jul 30 '20 at 15:46
  • A tip about bitfields: until you really, really need them (i.e., you're doing hardware bit bashing), forget that they exist. They're quirky, not portable, and unintuitive. – Pete Becker Jul 30 '20 at 17:28

2 Answers2

3

The example on cppreference just tells that there is no guarantee in the standard that bitfields are mapped to adjacent memory regions, although most sensible implementations would do that. An code snippet provided deliberately uses an unnamed bitfiled of 2 bits to request two bits from the storage - and just showcases that bitfileds could be unnamed. This makes the total number of bits required to represent this structure 14.

14 bits could be packed into 2 bytes (16 bits), so this is what is expected of an average implementation - but it is not guaranteed to be happening.

Last, but not the least, if you find yourself in a position of using bitfields on a struct, think not twice, but triple. There are very few scenarios when they actually provide advantage, so you need to be sure you are dealing with one of those.

SergeyA
  • 61,605
  • 5
  • 78
  • 137
2

The example you quoted is being used to explain that multiple bit-fields are usually (not necessarily) packed together. If you look at it more carefully:

    // 3 bits: value of b1      - 3 bits occupied
    // 2 bits: unused           - 2 bits left unused
    // 6 bits: value of b2      - 6 bits occupied (these 6 can't fit into the previous byte
                                as 5 bits are already occupied. What will happen in this 
                                case? Will these 6 bits go into the next byte? Will they
                                somehow *overlap* two bytes?
    // 2 bits: value of b3       
    // 3 bits: unused

If the result of sizeof(S) == 2 is true, then we can say that the field b2 is straddling bytes. The example is trying to explain this concept.

The example is not so clear at explaining this, so let me create a slightly better one:

struct S {
    unsigned char b1 : 3, : 2, b2 : 6, b3 : 3;
};

The difference is b3 is now 3 bits. Total bits of the struct = 3 + 2 + 6 + 3 = 14. If I print the sizeof (S) now, I get, 3 as output which tells me there is no byte straddling on my system.

Furthermore, You can find this at the bottom of the page:

  • Everything about the actual allocation details of bit fields within the class object
    • For example, on some platforms, bit fields don't straddle bytes, on others they do
    • Also, on some platforms, bit fields are packed left-to-right, on others right-to-left

Could anyone explain me if (if I am not wrong) this bit fields actually change the size of the variable or they are just a "suggestion" for the compiler? (as inline keyword). If bit fields works as I understand, you would be able to stor a boolean on 1 bit (which is not possible because the memory is splitted on chunks of 1 bytes)

Almost everything about bit-fields is implementation defined so to get the correct answers you will have to look at each compiler's documentation and read the ABI documents to get the answer. For example, this is from GCC docs:

Whether a bit-field can straddle a storage-unit boundary (C90 6.5.2.1, C99 and C11 6.7.2.1).
Determined by ABI.

If we look at the assembly generated for GCC 10.1, we can see that the bit-fields are actually being used:

        # b1: 1, b2: 61, b3: 3

        sub     rsp, 24
        mov     eax, -767
        lea     rdi, [rsp+14]
        mov     WORD PTR [rsp+14], ax

The number -767 in binary:

b3  b6    b1
11 111101 00000001

boolean on 1 bit

The answer would not be complete without mentioning std::vector<bool> which tried to do this, but it turned out that it was not such a great idea.

Waqar
  • 8,558
  • 4
  • 35
  • 43