Practical Use of Zero-Length Bitfields

2020-01-24 09:15发布

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 :)

标签: c++ c bit-fields
5条回答
你好瞎i
2楼-- · 2020-01-24 09:45

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 as

struct {
  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-fields d and e.ee are each separate memory locations, and can be modified concurrently without interfering with each other. The bit-fields b and c together constitute the fourth memory location. The bit-fields b and c cannot be concurrently modified, but b and a, 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.

查看更多
何必那么认真
3楼-- · 2020-01-24 09:51

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.

查看更多
闹够了就滚
4楼-- · 2020-01-24 09:55
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); }))
查看更多
Ridiculous、
5楼-- · 2020-01-24 09:56

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;
};
查看更多
走好不送
6楼-- · 2020-01-24 10:04

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.

登录 后发表回答