c – 不能取位域的地址

为什么不能取位域的地址?

如何制作指向位字段的指针?

这是代码……

struct bitfield { unsigned int a: 1; unsigned int b: 1; unsigned int c: 1; unsigned int d: 1; }; int main(void) { struct bitfield pipe = { .a = 1, .b = 0, .c = 0, .d = 0 }; printf("%d %d %d %d\n", pipe.a, pipe.b, pipe.c, pipe.d); printf("%p\n", &pipe.a); /* OPPS HERE */ // error: cannot take address of bit-field ... return 0; } 

Bitfields成员(通常)小于指针允许的粒度,这是char的粒度(通过char定义 ,顺便说一下,它至少要求为8位长)。 因此,常规指针不会削减它。

此外,还不清楚指向位域成员的指针类型是什么,因为要存储/检索这样的成员,编译器必须确切地知道它在位域中的位置(并且没有“常规”指针类型可以携带此类信息)。

最后,它几乎不是一个要求的function(首先不会经常看到位域); bitfields用于紧凑地存储信息或构建标志的打包表示(例如写入硬件端口),很少需要指向它们的单个字段的指针 – 如果需要,你总是可以诉诸常规struct并在最后一刻转换为位域。

由于所有这些原因,该标准表明位域成员不可寻址,周期。 有可能克服这些障碍(例如,通过定义存储访问位域成员所需的所有信息的特殊指针类型),但这将是没有人使用的语言的另一个过于复杂的黑暗角落。

您不能拥有位字段的地址,因为最小的可寻址单位是一个字节(记住C中的字节可能不一定是8位宽)。

您可能希望的最好的是包含结构的地址。

(C11)标准的相关部分是6.5.3.2 Address and indirection operators6.5.3.2 Address and indirection operators (我的斜体):

一元&运算符的操作数应该是函数指示符, []或一元*运算符的结果,或者是一个lvalue ,它指定一个不是位字段的对象,并且不用寄存器存储类说明符声明。

鉴于最小的可寻址性是一个字节,你可能会发现你的bitfileds被压缩:

 Addr\Bit 7 6 5 4 3 2 1 0 00001234 | a | b | c | d | ? | ? | ? | ? | 00001235 | | | | | | | | | 

你可以看到所有那些bitfileds的地址实际上是相同的,所以它并没有那么有用。

对于操作bitfileds,你真的应该直接访问它们并让编译器对它们进行排序。 即使使用按位运算符也不能保证工作,除非您知道编译器如何将它们放在内存中。

地址必须是整数个字节,但不一定是位字段,因此C标准指定地址运算符&不能与它们一起使用。 当然,如果你真的想用位域地址做事情,你可以使用封闭结构的地址,并进行一些按位操作。

在类似的说明中,如果你只是想解决单个字节,你可以这样做:

 union PAIR { struct { uint8_t l, h; } b; uint16_t w; }; PAIR ax; 

您现在可以访问像&ax.w,&ax.bl或&ax.bh这些部分的指针,注意这仍然不允许您指向单个位,请参阅之前的解释。

编辑:修复示例