零长度位字段的实际使用 我不完全肯定C,但是C++允许0长度的未命名位字段。例如: struct X { int : 0; }; struct W { int a:1; int :0; }; // OK struct X { int :0; }; // Undefined Behavior 问题一:你能想到它的实际用途吗? 问题二:您知道哪些实际用途(如有)?
编辑冰上犯罪答案后的例子 编辑:好的,由于当前的答案,我现在知道了理论目的。但是问题是关于实际用途的,所以它们仍然适用:)标准(9.6/2)只允许0长度的位字段作为一种特殊情况: 作为特例,一个未命名的 宽度为零的位字段 指定下一个对象的对齐方式 分配单元上的位字段 边界仅在声明 未命名的位字段可能是 常量表达式的值必须等于 归零 虽然我还没有在实际代码中遇到过它,但在这段引用中描述了它的唯一用途零长度位字段的实际使用 我不完全肯定C,但是C++允许0长度的未命名位字段。例如: struct X { int : 0; }; struct W { int a:1; int :0; }; // OK struct X { int :0; }; // Undefined Behavior 问题一:你能想到它的实际用途吗? 问题二:您知道哪些实际用途(如有)?,c++,c,bit-fields,C++,C,Bit Fields,编辑冰上犯罪答案后的例子 编辑:好的,由于当前的答案,我现在知道了理论目的。但是问题是关于实际用途的,所以它们仍然适用:)标准(9.6/2)只允许0长度的位字段作为一种特殊情况: 作为特例,一个未命名的 宽度为零的位字段 指定下一个对象的对齐方式 分配单元上的位字段 边界仅在声明 未命名的位字段可能是 常量表达式的值必须等于 归零 虽然我还没有在实际代码中遇到过它,但在这段引用中描述了它的唯一用途 为了记录在案,我刚刚在VS 2010下尝试了以下代码: struct X { int i
为了记录在案,我刚刚在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;
}
struct X{
int i:3,j:5;
};
结构{
int i:3,:0,j:5;//语法不错,是吧?
};
int main()
{
STD::CUT< P>这是来自MSDN的,没有标记为微软特定的,所以我猜这是普通的C++标准:
宽度为0的未命名位字段将强制下一个位字段与下一个类型边界对齐,其中类型是成员的类型。使用零长度位字段是一种让编译器布局结构以匹配某些外部要求(无论是另一个编译器还是体系结构的布局概念)的黑客方法(跨平台数据结构,如二进制文件格式)或位级标准要求(网络数据包或指令操作码)
一个真实的例子是下一次从摩托罗拉68000(m68k)移植xnu内核时i386架构的架构。NeXT有一个可用的m68k版本的内核。当他们将其移植到i386时,他们发现i386的对齐要求与m68k不同,m68k机器和i386机器在下一个特定于供应商的BOOTP结构的布局上不一致。为了使i386结构布局与m68k一致,他们添加了一个长度为零的未命名位字段,以强制NV1
structure/NVU
并集对齐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;
};
是C中未定义的行为
见(我的重点):
(C99,6.7.2.1p2)“结构或联合说明符中存在的结构声明列表在翻译单元中声明了一个新类型。结构声明列表是结构或联合成员的声明序列。如果结构声明列表不包含命名成员,则行为未定义。”
(C11具有相同的措辞。)
可以使用宽度为0
的未命名位字段,但如果结构中没有其他命名成员,则不能使用
例如:
struct X
{
int : 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); }))
C11标准现在允许包含零长度的位字段
3.14内存位置
…
4.示例声明为
struct {
char a;
int b:5, c:11, :0, d:8;
struct { int ee:8; } e;
}
包含四个独立的内存位置:成员a
,位字段d
和e.ee
都是独立的内存位置,可以在不相互干扰的情况下同时修改。位字段b
和c
共同构成第四个内存位置。位字段b代码>和c
不能同时修改,但是可以同时修改b
和a
因此,在位域c
和d
之间包含零长度位域,允许同时修改b
和d
。C99允许零长度数组更好地支持动态大小的结构。@roe:是的,它相当于0长度的动态分配数组,这是您真的很有用。我认为这里的问题是位字段长度必须是编译时常量。@roe:您的注释不正确。C不允许在任何版本的标准中使用char a[0];
。另一方面,char a[]在C99的结构中允许使用
;它被称为灵活数组成员,必须出现在末尾。
字符a[];
不是“字符a[0]的简写形式;”.@R,我的错,我错了;使用zero是GCC特定的扩展。从技术上讲,它仍然是一个零长度数组,尽管最初的问题是不可能的。我知道它必须位于结构的末尾(其他任何地方都没有任何意义)@R:C要求的数组必须具有非零大小,这太糟糕了,因为最常见的绕过零大小数组禁令的黑客行为的流行阻止了编译器进行一些其他有用的优化。例如,如果struct foo以“int bar[1]”结尾,则表达式“foo.bar[i]”可以合法地替换为“foo.bar”[0]“可以在编译时进行计算(因为“i”的任何其他值都会调用未定义的行为)当然,结构黑客非常常见,任何利用这种优化的编译器都会破坏真实世界的代码。一个实际示例:+1;也许您可以提到它更详细地描述了该宏。对于BUILD\u BUG\u ON\u ZERO