Practical Use of Zero-Length Bitfields
I am not totally sure about C, but C++ allows unnamed bit-fields of 0 length. For example:
struct X
{
int : 0;
};
- Question one: What practical uses of this can you think of?
- Question two: What real-world practical uses (if any) are you aware of?
Edited the example after ice-crime's answer
Edit: OK, thanks to the current answers I now know the theoretical purpose. But the questions are about practical uses so they still hold :)
You use a zero-length bitfield as a hacky way to get your compiler to lay out a structure to match some external requirement, be it another compiler's or architecture's notion of the layout (cross-platform data structures, such as in a binary file format) or a bit-level standard's requirements (network packets or instruction opcodes).
A real-world example is when NeXT ported the xnu kernel from the Motorola 68000 (m68k) architecture to the i386 architecture. NeXT had a working m68k version of their kernel. When they ported it to i386, they found that the i386's alignment requirements differed from the m68k's in such a way that an m68k machine and an i386 machine did not agree on the layout of the NeXT vendor-specific BOOTP structure. In order to make the i386 structure layout agree with the m68k, they added an unnamed bitfield of length zero to force the NV1
structure/nv_U
union to be 16-bit aligned.
Here are the relevant parts from the Mac OS X 10.6.5 xnu source code:
/* from xnu/bsd/netinet/bootp.h */
/*
* Bootstrap Protocol (BOOTP). RFC 951.
*/
/*
* HISTORY
*
* 14 May 1992 ? at NeXT
* Added correct padding to struct nextvend. This is
* needed for the i386 due to alignment differences wrt
* the m68k. Also adjusted the size of the array fields
* because the NeXT vendor area was overflowing the bootp
* packet.
*/
/* . . . */
struct nextvend {
u_char nv_magic[4]; /* Magic number for vendor specificity */
u_char nv_version; /* NeXT protocol version */
/*
* Round the beginning
* of the union to a 16
* bit boundary due to
* struct/union alignment
* on the m68k.
*/
unsigned short :0;
union {
u_char NV0[58];
struct {
u_char NV1_opcode; /* opcode - Version 1 */
u_char NV1_xid; /* transcation id */
u_char NV1_text[NVMAXTEXT]; /* text */
u_char NV1_null; /* null terminator */
} NV1;
} nv_U;
};
The standard (9.6/2) only allows 0 length bit-fields as a special case :
As a special case, an unnamed bit-field with a width of zero specifies alignment of the next bit-field at an allocation unit boundary. Only when declaring an unnamed bit-field may the constant-expression be a value equal to zero.
The only use is described in this quote, although I've never encountered it in practical code yet.
For the record, I just tried the following code under VS 2010 :
struct X {
int i : 3, j : 5;
};
struct Y {
int i : 3, : 0, j : 5; // nice syntax huh ?
};
int main()
{
std::cout << sizeof(X) << " - " << sizeof(Y) << std::endl;
}
The output on my machine is indeed : 4 - 8
.
struct X { int : 0; };
is undefined behavior in C.
See (emphasis mine):
(C99, 6.7.2.1p2) "The presence of a struct-declaration-list in a struct-or-union-specifier declares a new type, within a translation unit. The struct-declaration-list is a sequence of declarations for the members of the structure or union. If the struct-declaration-list contains no named members, the behavior is undefined"
(C11 has the same wording.)
You can use an unnamed bit-field with 0
width but not if there is no other named member in the structure.
For example:
struct W { int a:1; int :0; }; // OK
struct X { int :0; }; // Undefined Behavior
By the way for the second declaration, gcc
issues a diagnostic (not required by the C Standard) with -pedantic
.
On the other hand:
struct X { int :0; };
is defined in GNU C. It is used for example by the Linux kernel (include/linux/bug.h
) to force a compilation error using the following macro if the condition is true:
#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
This is from MSDN and not marked as Microsoft Specific, so I guess this is common C++ standard:
An unnamed bit field of width 0 forces alignment of the next bit field to the next type boundary, where type is the type of the member.
The C11 standard now allows the inclusion of zero length bitfields. Here is an example from the C Committee draft (N1570), which I believe illustrates a practical usage.
3.14 memory location
...
4. EXAMPLE A structure declared asstruct { char a; int b:5, c:11, :0, d:8; struct { int ee:8; } e; }
contains four separate memory locations: The member
a
, and bit-fieldsd
ande.ee
are each separate memory locations, and can be modified concurrently without interfering with each other. The bit-fieldsb
andc
together constitute the fourth memory location. The bit-fieldsb
andc
cannot be concurrently modified, butb
anda
, for example, can be.
So including the zero length bitfield in between the bitfields c
and d
allows the concurrent modification of b
and d
as well.