What does an unnamed zero length bit-field mean in C?

3.2k Views Asked by At

I saw the following example in the C standard draft (n1570):

$3.14 paragraph 4 : A structure declared as:

struct 
{
        char a;
        int b:5, c:11, :0, d:8;
        struct 
        { 
            int ee:8; 
        } e;
}

So, What does :0 mean?

I know what a bit-field is, but :0 is without a name, which I do not understand.

What is the purpose of :0 without any identifier?

3

There are 3 best solutions below

8
Sourav Ghosh On BEST ANSWER

First of all, let's see chapter §6.7.2.1, Structure and union specifiers, P11. It says,

An implementation may allocate any addressable storage unit large enough to hold a bitfield. 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. [...]

But, in case, we explicitly want two consecutive bit-field members, which "might be" packed into a single memory location to reside on separate memory location (i.e., addressable storage unit ), the above is the way to force it.

The next paragraph, P12, mentions,

A bit-field declaration with no declarator, but only a colon and a width, indicates an unnamed bit-field.126) 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.

following your example, this makes sure that the two bit-field members surrounding the :0 will be residing in separate memory location (not inside a single addressable storage unit, even if sufficient memory remains to pack them into one). This has the similar effect of having a non-bit-field member in between two bit-fields, to force the separation of the memory location.

Quoting C11, chapter §3.14, NOTE 2 (emphasis mine)

A bit-field and an adjacent non-bit-field member are in separate memory locations. The same applies to two bit-fields, if one is declared inside a nested structure declaration and the other is not, or if the two are separated by a zero-length bit-field declaration, or if they are separated by a non-bit-field member declaration.

Also, regarding the usage ("why it is needed" part)

[...] The bit-fields b and c cannot be concurrently modified, but b and a, for example, can be.


Addendum:

Regarding the concurrency part, from NOTE 1

Two threads of execution can update and access separate memory locations without interfering with each other.

and, from chapter §5.1.2.4/P1,

Under a hosted implementation, a program can have more than one thread of execution (or thread) running concurrently. [...]

So, this is a theoretically viable option, as per the standard.

2
Sami Kuhmonen On

As the document you linked explains right before:

A bit-field and an adjacent non-bit-field member are in separate memory locations. The same applies to two bit-fields, if one is declared inside a nested structure declaration and the other is not, or if the two are separated by a zero-length bit-field declaration, or if they are separated by a non-bit-field member declaration

It is a way to tell the compiler that b and c can/will be in the same memory location whereas d must be separate from them and can be modified concurrently to b/c

0
paxdiablo On

It's a way of ensuring that bit-fileds, that might otherwise be combined into a single memory location, are not.

For example, let's say you have an 8-bit character but you wanted to ensure your two 3-bit fields were at separate locations (and thus could be modified concurrently). To achieve that, you could use:

struct xyzzy {
    int first  : 3,
               : 0,
    int second : 3;
};

and you wouldn't have to worry about filling out the space manually, such as with junk : 5.

For the language lawyers, C11 3.14 memory location /3 states (my emphasis):

A bit-field and an adjacent non-bit-field member are in separate memory locations. The same applies to two bit-fields, if one is declared inside a nested structure declaration and the other is not, or if the two are separated by a zero-length bit-field declaration, or if they are separated by a non-bit-field member declaration.