How do bit fields interplay with bits padding in C

2019-07-10 11:35发布

问题:

I have two questions concerning bit fields when there are padding bits.

Say I have a struct defined as

struct T { 
    unsigned int x: 1; 
    unsigned int y: 1;
};

Struct T only has two bits actually used.

Question 1: are these two bits always the least significant bits of the underlying unsigned int? Or it is platform dependent?

Question 2: Are those unused 30 bits always initialized to 0? What does the C standard say about it?

回答1:

Question 1: are these two bits always the least significant bits of the underlying unsigned int? Or it is platform dependent?

No, it is both system and compiler dependent. You can never assume or know that they are MSB or LSB.

Question 2: Are those unused 30 bits always initialized to 0? What do the C and C++ standards say about it?

Depends on how you initialize the struct. A struct at local scope which isn't initialized may contain garbage values in padding bits/bytes. A struct that is initialized with at least one initializer set, is guaranteed to contain zero even in padding bytes: my_struct = { something };.


Sources

The language-lawyer details of why the above works are somewhat complex.

C17 6.7.9/9 (emphasis mine) says this:

Except where explicitly stated otherwise, for the purposes of this subclause unnamed members of objects of structure and union type do not participate in initialization. Unnamed members of structure objects have indeterminate value even after initialization.

This means that we cannot trust padding bits/bytes at all. But then there's this exception to the above rule (§20 emphasis mine):

If there are fewer initializers in a brace-enclosed list than there are elements or members of an aggregate, or fewer characters in a string literal used to initialize an array of known size than there are elements in the array, the remainder of the aggregate shall be initialized implicitly the same as objects that have static storage duration.

Meaning that if there's at least one initializer, then the following rule of static storage initialization applies:

C17 6.7.9/10 (emphasis mine):

If an object that has static or thread storage duration is not initialized explicitly, then: /--/

  • if it is an aggregate, every member is initialized (recursively) according to these rules, and any padding is initialized to zero bits;