33

我对 C 不太确定,但 C++ 允许长度为 0 的未命名位域。例如:

struct X
{
    int : 0;
};
  • 问题一:你能想到这个有什么实际用途?
  • 问题二:您知道哪些现实世界的实际用途(如果有)?

在冰罪的回答之后编辑了这个例子

编辑:好的,感谢当前的答案,我现在知道了理论目的。但问题是关于实际用途的,所以它们仍然成立:)

4

5 回答 5

34

您使用零长度位域作为一种 hacky 方式让您的编译器布局结构以匹配某些外部要求,无论是另一个编译器或架构的布局概念(跨平台数据结构,例如二进制文件格式) 或位级标准的要求(网络数据包或指令操作码)。

一个真实的例子是 NeXT 将 xnu 内核从 Motorola 68000 (m68k) 架构移植到 i386 架构。NeXT 有一个工作的 m68k 版本的内核。当他们将其移植到 i386 时,他们发现 i386 的对齐要求与 m68k 的不同之处在于 m68k 机器和 i386 机器在 NeXT 供应商特定 BOOTP 结构的布局上没有达成一致。为了使 i386 结构布局与 m68k 一致,他们添加了一个长度为零的未命名位域,以强制NV1结构/nv_U联合为 16 位对齐。

以下是 Mac OS X 10.6.5 xnu 源代码中的相关部分:

/* 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;
};
于 2010-11-28T17:59:02.683 回答
25

标准(9.6/2)只允许长度为 0 的位域作为特例

作为一种特殊情况,宽度为零的未命名位域指定下一个位域在分配单元边界处的对齐方式。只有在声明未命名的位域时,常量表达式才可以是等于零的值

这个引用中描述了唯一的用途,尽管我还没有在实际代码中遇到过它。


作为记录,我刚刚在 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;
}

我机器上的输出确实是:4 - 8

于 2010-11-28T14:04:46.890 回答
11
struct X { int : 0; };

是 C 中未定义的行为。

见(强调我的):

(C99,6.7.2.1p2)“结构或联合说明符中的结构声明列表的存在声明了翻译单元内的新类型。结构声明列表是声明的序列结构或联合的成员。如果 struct-declaration-list 不包含命名成员,则行为未定义

(C11 的措辞相同。)

您可以使用0带宽度的未命名位域,但如果结构中没有其他命名成员则不能。

例如:

struct W { int a:1; int :0; };  // OK
struct X { int :0; };           // Undefined Behavior

顺便说一下,对于第二个声明,gcc使用-pedantic.

另一方面:

 struct X { int :0; };

在 GNU C 中定义。例如,Linux 内核 ( include/linux/bug.h) 使用它来强制编译错误,如果条件为真,则使用以下宏:

#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
于 2012-10-16T16:08:58.157 回答
7

这是来自 MSDN 并且没有标记为 Microsoft 特定,所以我想这是常见的 C++ 标准:

宽度为 0 的未命名位域强制下一个位域与下一个类型边界对齐,其中 type 是成员的类型。

于 2010-11-28T14:05:49.120 回答
2

C11 标准现在允许包含零长度位域。这是 C 委员会草案 (N1570) 中的一个示例,我相信它说明了实际用法。

3.14 内存位置
...
4. 示例 声明为的结构

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

包含四个独立的内存位置:成员a和位域de.ee每个都是独立的内存位置,可以同时修改而不会相互干扰。位域bc一起构成第四个存储位置。位域bc不能同时修改,但是ba,例如,可以。

因此,在位域之间包括零长度位域,cd允许同时修改band d

于 2018-09-27T10:44:13.147 回答