I am working with structs in c on linux.
I started using bit fields and the "packed" attribute and I came across a wierd behavior:
struct t1
{
int a:12;
int b:32;
int c:4;
}__attribute__((packed));
struct t2
{
int a:12;
int b;
int c:4;
}__attribute__((packed));
void main()
{
printf("%d\n",sizeof(t1)); //output - 6
printf("%d\n",sizeof(t2)); //output - 7
}
How come both structures - that are exactly the same - take diffrent number of bytes?
Your structures are not "exactly the same". Your first one has three consecutive bit-fields, the second has one bit-field, an (non bit-field) int, and then a second bit-field.
This is significant: consecutive (non-zero width) bit-fields are merged into a single memory location, while a bit-field followed by a non-bit-field are distinct memory locations.
Your first structure has a single memory location, your second has three. You can take the address of the b
member in your second struct, not in your first. Accesses to the b
member don't race with accesses the a
or c
in your second struct, but they do in your first.
Having a non-bit-field (or a zero-length bit-field) right after a bit-field member "closes" it in a sens, what follow will be a different/independent memory location/object. The compiler cannot "pack" your b
member inside the bit-field like it does in the first struct.
struct t1 // 6 bytes
{
int a:12; // 0:11
int b:32; // 12:43
int c:4; // 44:47
}__attribute__((packed));
struct t1 // 7 bytes
{
int a:12; // 0:11
int b; // 16:47
int c:4; // 48:51
}__attribute__((packed));
The regular int b
must be aligned to a byte boundary. So there is padding before it. If you put c
right next to a
this padding will no longer be necessary. You should probably do this, as accessing non-byte-aligned integers like int b:32
is slow.