为什么某些结构具有零宽度位域,为什么需要它?
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 :(得分:9)
来自this first hit on a Google search:
长度为0的位字段必须是未命名的。无法引用或初始化未命名的位字段。零宽度位字段可以使下一个字段在下一个容器边界上对齐,其中容器的大小与位字段的基础类型相同。
至于问题的第二部分,您将结构中位域的部分设置为全1,并且由于这些字段已签名,因此这将导致这些字段的负值。如果将整个结构设置为1并查看有符号和无符号表示中的值,则可以更有效地看到这一点,例如。
int main()
{
struct foo f;
memset(&f, 0xff, sizeof(f));
printf("a=%d\nb=%d\nc=%d\nd=%d\n", f.a, f.b, f.c, f.d); // print fields as signed
printf("a=%u\nb=%u\nc=%u\nd=%u\n", f.a, f.b, f.c, f.d); // print fields as unsigned
return 0;
}
答案 1 :(得分:3)
内存布局是“它依赖”,你不能指望任何特定编译器的任何特定布局。实际上,通过更改其设置,您可能会看到来自任何给定编译器的不同布局。不要试图猜测,直觉或依赖于布局。
否定 - 所有元素都是int
s已签名,因此它们是负数,因为您已将每个位初始化为1,因此您已设置符号位。至于d - 打败了我。错字?
答案 2 :(得分:2)
如上所述here,零长度位域增加了位域之间的对齐。如果我们连续有几个位域,它们的布局是紧凑的,但是如果我们想将它们中的一个对齐到字节/字/双字边界,我们需要在它和前一个之间放置一个零长度的位域。
以上链接中的示例:
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 ;
答案 3 :(得分:1)
数字是负数,因为位域是有符号的,即如果你有一个signed char
变量,它的大小是8位,可以容纳256个不同的值。一半的值是正数,其余的是负数和0.最高有效位表示符号(1表示负数,0表示正数)。关于零长度位域,请参见此处:Practical Use of Zero-Length Bitfields