零长度位域的实际应用

我不完全确定C,但C ++允许未命名的0字段位字段。 例如:

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

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

编辑:好的,多亏了目前的答案,我现在知道了理论目的。 但问题是关于实际用途,所以他们仍然持有:)

您使用零长度位域作为一种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; }; 

标准(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

 struct X { int : 0; }; 

是C中未定义的行为。

见(强调我的):

(C99,6.7.2.1p2)“struct-or-union-specifier中struct-declaration-list的存在在转换单元中声明了一个新类型.struct-declaration-list是一个声明序列。结构或联合的成员。 如果struct-declaration-list不包含命名成员,则行为未定义

(C11的措辞相同。)

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

例如:

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

顺便说一下,第二次声明, gcc发出了一个诊断(C标准不要求)和-pedantic

另一方面:

  struct X { int :0; }; 

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

 #define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); })) 

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

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

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之间包括零长度位域允许同时修改bd