问题
Program is in C using std=c99, this is on a 64-bit machine.
struct epochs {
volatile unsigned int epoch : 1;
volatile unsigned int pulse : 1;
volatile unsigned int active0 : 7;
volatile unsigned int active1 : 7;
volatile unsigned int counter0 : 24;
volatile unsigned int counter1 : 24;
};
when I check sizeof(epochs) it gives me 12.
I can tell gcc not to pad it by adding __attribute((packed)); so I can work around it. However I would really like to know why 4 bytes are added to pad this 64-bit structure?
The main thing here is that this structure NEEDS to be 64 bits because it is updated all at once in 64-bit atomic swap operations, which of course will not work on a 12-byte value.
回答1:
volatile unsigned int epoch : 1;
volatile unsigned int pulse : 1;
volatile unsigned int active0 : 7;
volatile unsigned int active1 : 7;
^ 32-bit (4 bytes)
volatile unsigned int counter0 : 24;
^ 32-bit (4 bytes)
volatile unsigned int counter1 : 24;
^ 32-bit (4 bytes)
So 4 bytes more.
C says :
(C99, 6.7.2.1p10) "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"
There is not enough space to put 24-bit (counter0
) more in a 32-bit unit (likely the size of unsigned int
in your system) that already holds 16-bit (epoch
, pulse
, active0
, active1
).
You can use uin64_t
instead of using unsigned int
to pack your bit-fields in a 64-bit unit but it is implementation-defined whether your system supports it or not.
(C99, 6.7.2.1p4) "A bit-field shall have a type that is a qualified or unqualified version of _Bool, signed int, unsigned int, or some other implementation-defined type."
回答2:
While some older compilers used to regard int foo:3;
as synonymous with e.g. long foo:3
, or short foo:3
, and simply place foo
in whatever manner was convenient, the present C standard specifies that each bit field must fit entirely within a storage unit of the appropriate size. I have no idea what the rationale was for that specification, since the way bit fields are specified remains too vague to allow their use in portable code, but sometimes makes it impossible to pack things optimally. For example, the only way a 24-bit value could be stored efficiently within a structure would be to either have a machine which on a machine which supports 32-bit integers, or else have a 8 bits of data which could be placed adjacent to the 24-bit value (preceding or following) so as to "fill out" a 32-bit word.
Fortunately, in your particular case, it's possible to avoid the inefficiency by rearranging your fields. It may also be possible to avoid the inefficiency by changing the declared type of each field to unsigned long long
if your compiler supports bitfields using such a type [in that case, bit fields would be allowed to straddle 32-bit boundaries provided they didn't straddle a 64-bit boundary].
来源:https://stackoverflow.com/questions/19323138/why-does-gcc-pad-this-bit-field