Re:The Lost Art of Structure Packing (2018)
by kazinator on Monday April 27, 2020 @01:43PM
(#22998059)
I tried numerous cases, and looked at the memory, and also read and wrote the structures with FFI to make sure they match what the C compiler is putting out, and fixed bugs along the way. For big endian investiations, I borrowed the big endian PPC machine courtesy of the GCC Compile Farm project.
The details are not obvious; like the fact that a zero width bitfield like "int : 0" that appears etween two members that are not bitfields actually does something. E.g. this has size 5:
struct {
char c1;
int : 0; // zero-width bit-field must be unnamed
char c2;
};
This is basically because c1 is de-facto considered to be 8 allocated bits out of an int-wide cell, leaving 24 bits in that cell. The int : 0 sees that a field has been partially filled and so increments to the next int-wide field (according to my documented hypothesis).
ISO C says (or did say in 1999) only this: "A bit-field declaration with no declarator, but only a colon and a width, indicates an unnamed bit-field.105) As a special case, a bit-field structure member with a width of 0 indicates that no further bit-field is to be packed into the unit in which the previous bit-field, if any, was placed."
No "further bit-field" is to be packed, but in this example there is neither a previous nor next bit field. So you might expect that there is no effect. In the GCC model of "all allocated so far are just bits", it has an effect.
Footnote 105 says just that "An unnamed bit-field structure member is useful for padding to conform to externally imposed layouts" which is more or less self-evident.
Oh wow; I just realized that the empty bit-field has an effect if it is the last member also:
struct { // now size 8!
char c1;
int : 0;
char c2;
int : 0;
};
This is predicted by my documentation, but it should be spelled out in an explicit remark.
It's a useful feature of GCC bit-fields because you can conform to certain external layouts without having to use bit-fields at all, other than the zero-width ones.
The details are not obvious; like the fact that a zero width bitfield like "int : 0" that appears etween two members that are not bitfields actually does something. E.g. this has size 5:
This is basically because c1 is de-facto considered to be 8 allocated bits out of an int-wide cell, leaving 24 bits in that cell. The int : 0 sees that a field has been partially filled and so increments to the next int-wide field (according to my documented hypothesis).ISO C says (or did say in 1999) only this: "A bit-field declaration with no declarator, but only a colon and a width, indicates an unnamed bit-field.105) As a special case, a bit-field structure member with a width of 0 indicates that no further bit-field is to be packed into the unit in which the previous bit-field, if any, was placed."
No "further bit-field" is to be packed, but in this example there is neither a previous nor next bit field. So you might expect that there is no effect. In the GCC model of "all allocated so far are just bits", it has an effect.
Footnote 105 says just that "An unnamed bit-field structure member is useful for padding to conform to externally imposed layouts" which is more or less self-evident.
Oh wow; I just realized that the empty bit-field has an effect if it is the last member also:
This is predicted by my documentation, but it should be spelled out in an explicit remark.It's a useful feature of GCC bit-fields because you can conform to certain external layouts without having to use bit-fields at all, other than the zero-width ones.