Issue 1076: Bit-field storage issues

Authors: Jay Ghiron
Date: 2026-06-09
Submitted against: C23
Status: Open

Question 1

Unsigned bit-fields have their representation described as such:

Values stored in unsigned bit-fields and objects of type unsigned char shall be represented using a pure binary notation.

(C23 6.2.6.1 "General" paragraph 3.)

However there is no equivalent wording for signed bit-fields, is this omission intentional? For example, would a gray code representation of signed bit-fields be valid? More importantly, there does not seem to be anything guaranteeing that setting all of the bytes of a structure to zero by using memset will result in its signed bit-fields each having the value zero.

Question 2

Values stored in bit-fields consist of m bits, where m is the size specified for the bit-field. The object representation is the set of m bits the bit-field comprises in the addressable storage unit holding it.

(C23 6.2.6.1 "General" paragraph 4.)

What does the addressable storage unit holding a bit-field mean if the bit-field straddles multiple storage units?

Question 3

The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined.

(C23 6.7.3.2 "Structure and union specifiers" paragraph 13.)

Are the two orders listed here in the parentheses exhaustive? That is, can other orders be used?

Question 4

A pointer to a structure object, suitably converted, points to its initial member (or if that member is a bit-field, then to the unit in which it resides), and vice versa.

(C23 6.7.3.2 "Structure and union specifiers" paragraph 17.)

For strictly conforming programs, is it even possible to know what the type of the storage unit is? If not, is there any purpose in trying to define this?

If the initial member is an unnamed bit-field of width zero, what storage unit does it reside in? If the first member is an unnamed bit-field of width zero and the second member is not a bit-field, there does not even appear to be any storage unit for it to reside in. In that scenario, perhaps it should be required for a pointer to an object with that structure type to also point to its second member when suitably converted.

Question 5

Do the bits in the storage units containing a bit-field which are not part of its object representation matter when accessing its value? For example:

int main(){
struct{unsigned x:1;}a;
*(unsigned char*)&a=0;
return a.x;
}

Assume that the one bit used is stored in the first byte, and that the size of the storage unit containing the bit-field is more than one byte. Is this guaranteed to return zero, or is it undefined?

Question 6

If the answer to question five is that other bits do not matter, how does copying around structures containing bit-fields by the object representations work? For example:

struct B{bool b:1;};
static_assert(sizeof(struct B)==1);
int main(){
struct B c,d;
c.b=0;
unsigned char e=*(unsigned char*)&c;
*(unsigned char*)&d=e;
return d.b;
}

If only one bit in c has a defined zero value and the other bits are indeterminate, it appears that e would have an indeterminate value. The standard does not have an idea of a partially indeterminate value, so it appears that the whole object representation of d is indeterminate making the program undefined if the other bits in c can be indeterminate. If that were the case, it would break using memcpy here so I assume it is not the intent.

Question 7

If the value 0 or 1 is stored into a nonzero-width bit-field of type bool, the value of the bit-field shall compare equal to the value stored; a bool bit-field has the semantics of a bool.

(C23 6.7.3.2 "Structure and union specifiers" paragraph 12.)

Should a bit-field of enumerated type compatible with bool have the same semantics as bool?

struct{enum:bool{f}g:1;}h;
/* assume this bit-field is supported */
int main(){
h.g=2;
return h.g;
/* is zero or one returned? */
}