Reputation: 1283
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)
Upvotes: 1
Views: 395
Reputation: 62583
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.
Upvotes: 3
Reputation: 9331
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.
Upvotes: 3