Reputation: 551
I found a code segment for a structure as below:
struct
{
__u8 saveable: 1;
__u8 namespace: 1;
__u8 changeable: 1;
__u32 reserved: 29;
};
I wonder what the difference is between that and the definition as below:
struct
{
__u32 saveable: 1;
__u32 namespace: 1;
__u32 changeable: 1;
__u32 reserved: 29;
};
Are there any possible reasons behind this?
Upvotes: 2
Views: 739
Reputation: 51815
Although the allocation of objects that contain bit-fields is implementation-defined, the C Standard does specify that consecutive bit-field members of a structure shall be packed into the same 'unit', if sufficient space remains in that unit.
From this Draft C11 Standard (bold emphasis mine):
6.7.2.1 Structure and union specifiers
…
11 An implementation may allocate any addressable storage unit large enough to hold a bit-field. If enough space remains, a bit-field that immediately follows another bit-field in a structure shall be packed into adjacent bits of the same unit. If insufficient space remains, whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is implementation-defined. The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined. The alignment of the addressable storage unit is unspecified.
Thus, in your first structure, the first three fields could be packed into one 8-bit unit but, then, the fourth must be placed in a separate, 32-bit unit (which will likely require 4-byte alignment, thus increasing the overall size of the structure to 8 bytes). What also may be significant in such a case is that padding bytes will be added to the structure, which may cause issues if your code relies on contiguous bits.
However, in the second case, all four bit-fields can be placed in a single 32-bit unit, so the structure size can be reduced to just 4 bytes.
But note that this may vary between compilers and platforms – notably, as demonstrated in the Compiler Explorer example linked in the comments, an implementation is entitled to allocate a 32-bit unit for the first three members of the first structure.
On Windows, using the clang-cl compiler in Visual Studio 2022, I get the aforementioned size difference between the structures when compiling and running the following code:
#include <stdint.h>
#include <stdio.h>
struct {
uint8_t saveable : 1;
uint8_t namespace : 1;
uint8_t changeable : 1;
uint32_t reserved : 29;
} s1;
struct {
uint32_t saveable : 1;
uint32_t namespace : 1;
uint32_t changeable : 1;
uint32_t reserved : 29;
} s2;
int main()
{
printf("Size of s1 = %zu\n", sizeof(s1));
printf("Size of s2 = %zu\n", sizeof(s2));
return 0;
}
Output:
Size of s1 = 8
Size of s2 = 4
Upvotes: 3