什么是零宽度位域

可能重复:
零长度位域的实际应用

为什么有些结构具有零宽度位域,为什么需要它?

struct foo { int a:3; int b:2; int :0; // Force alignment to next boundary. int c:4; int d:3; }; int main() { int i = 0xFFFF; struct foo *f = (struct foo *)&i; printf("a=%d\nb=%d\nc=%d\nd=%d\n", f->a, f->b, f->c, f->d); return 0; } 

上述程序的输出是

 manav@os-team:~/programs/test$ ./a.out a=-1 b=-1 c=-8 d=0 

请解释为什么这些值是负数,以及结构内部这些变量的内存布局?

从谷歌搜索的第一次打击 :

长度为0的位字段必须未命名。 无法引用或初始化未命名的位字段。 零宽度位字段可以使下一个字段在下一个容器边界上对齐,其中容器的大小与位字段的基础类型相同。

至于问题的第二部分,你将结构中的一些位域设置为全1,并且由于这些字段是有符号的,因此这会导致这些字段的负值。 如果将整个结构设置为1并查看有符号和无符号表示中的值,则可以更有效地查看此内容,例如

 int main() { struct foo f; memset(&f, 0xff, sizeof(f)); printf("a=%d\nb=%d\nc=%d\nd=%d\n", fa, fb, fc, fd); // print fields as signed printf("a=%u\nb=%u\nc=%u\nd=%u\n", fa, fb, fc, fd); // print fields as unsigned return 0; } 

内存布局是“它依赖”,你不能指望任何特定编译器的任何特定布局。 实际上,通过更改其设置,您可能会看到来自任何给定编译器的不同布局。 不要试图猜测,直觉或依赖于布局。

否定 – 所有元素都是有符号的int ,所以它们是负数,因为你已经将每个位初始化为1,所以你已经设置了符号位。 至于d – 打败了我。 错字?

如此处所述,零长度位域增加了位域之间的对齐。 如果我们连续有几个位域,它们的布局是紧凑的,但是如果我们想将它们中的一个对齐到字节/字/双字边界,我们需要在它和前一个之间放置一个零长度的位域。

上面的链接示例:

 struct on_off { unsigned light : 1; unsigned toaster : 1; int count; /* 4 bytes */ unsigned ac : 4; // this and unsigned : 4; // this and unsigned clock : 1; // this bitfields are next to each other unsigned : 0; unsigned flag : 1; // this bitfield is at a 4 bytes boundary. } kitchen ; 

数字是负数,因为位域是有符号的,即如果你有一个有signed char变量,它的大小是8位,可以容纳256个不同的值。 一半的值是正数,其余的是负数和0.最高有效位表示符号(1表示负数,0表示正数)。 关于零长度位域,请参见此处:零长度位域的实际应用