2010-11-28 59 views
19

我对C没有完全确定,但C++允许0长度的未命名位域。例如:零长度位域的实际应用

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

编辑冰犯罪的回答后,例如

编辑: OK,由于目前的答案,我现在知道了理论上的目的。但问题是关于实际用途,使他们仍然持有:)

+1

C99允许零长度数组更好地支持动态大小的结构。 – falstro 2010-11-28 14:02:15

+0

@roe:是的,它相当于0长度的动态分配数组,它非常有用。我认为这里的问题是位域长度必须是编译时常量。 – 2010-11-28 14:03:32

+6

@roe:您的评论不正确。 C **不允许在任何版本的标准中使用** char a [0];`另一方面,C99中的结构中允许使用`char a [];`;它被称为灵活的数组成员,并且必须出现在最后。 `char a [];`是** not ** a`简写为`char a [0];`“。 – 2010-11-28 14:57:41

回答

26

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

一个现实世界的例子是NeXT将xnu内核从摩托罗拉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; 
}; 
19

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

5

这是从MSDN和没有标记为微软特定,所以我想这是常见的C++标准:

下一比特字段的宽度0力对准的未命名的位字段到下一个类型边界,其中类型是成员的类型。

6
struct X { int : 0; }; 

是C.

见(重点煤矿)未定义的行为:

(C99,6.7.2.1p2)“struct-or-union-specifier中存在struct-declaration-list声明一个新类型,在一个转换单元中struct-声明列表是结构或联盟成员的一系列声明。 如果结构声明列表中没有名称的成员,该行为是未定义

(C11具有同样的措辞。)

您可以使用一个无名位字段与0宽度,但不如果在结构上没有其它命名构件

,例如:

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

顺便说为第二个声明,gcc使用-pedantic发布诊断(C标准未要求)。

在另一方面:

struct X { int :0; }; 

在GNU C中定义它用于例如通过Linux内核(include/linux/bug.h)使用以下宏,如果该条件为真,迫使编译错误:

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