为什么不能获取位字段的地址?
如何制作指向位字段的指针?
以下是代码......
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;
}
答案 0 :(得分:27)
Bitfields成员(通常)小于指针允许的粒度,这是char
的粒度(char
的定义,顺便提一下被授权至少8位长)。因此,常规指针不会削减它。
此外,还不清楚指向位域成员的指针类型是什么,因为要存储/检索这样的成员,编译器必须确切地知道它在位域中的位置(并且没有“常规”)指针类型可以携带这样的信息)。
最后,它几乎不是一个要求的功能(首先不会经常看到位域); bitfields用于紧凑地存储信息或构建标志的打包表示(例如写入硬件端口),很少需要指向单个字段的指针 - 如果需要,您可以随时使用常规struct
并在最后时刻转换为位域。
由于所有这些原因,该标准表明位域成员不可寻址,周期。 可能可以克服这些障碍(例如,通过定义存储访问位域成员所需的所有信息的特殊指针类型),但它将是该语言的另一个过于复杂的黑暗角落,没有人使用
答案 1 :(得分:7)
您不能拥有位字段的地址,因为最小的可寻址单位是一个字节(记住C中的字节可能不一定是8位宽)。
您可能希望的最好的是包含结构的地址。
(C11)标准的相关部分是6.5.3.2 Address and indirection operators
部分(我的斜体):
一元
&
运算符的操作数应该是函数指示符,是a的结果[]
或一元*
运算符,或lvalue
指定不位字段且未使用寄存器存储类说明符声明的对象
鉴于最小的可寻址性是一个字节,你可能会发现你的bitfileds压缩了:
Addr\Bit 7 6 5 4 3 2 1 0
00001234 | a | b | c | d | ? | ? | ? | ? |
00001235 | | | | | | | | |
你可以看到所有这些位文件的地址实际上是相同的,所以它并没有那么有用。
对于操作bitfileds,你真的应该直接访问它们并让编译器对它们进行排序。即使使用按位运算符也不能保证工作,除非你知道编译器如何将它们放在内存中。
答案 2 :(得分:5)
地址必须是整数个字节,但不一定是位字段,因此the C standard specifies地址运算符&
不能与它们一起使用。当然,如果你真的想用位域地址做事,你可以使用封闭结构的地址,并进行一些按位操作。
答案 3 :(得分:0)
您不能打印位字段的地址,但可以分配给某些需要的大小类型的局部变量(从1位内存到2个字节的类型转换(对于整数类型大小,取决于编译器)),可以用于打印地址。
unsigned int x = pipe.a; printf(“ x =%d”,&x);
答案 4 :(得分:-1)
在类似的说明中,如果你只想解决单个字节,你可以这样做:
union PAIR {
struct { uint8_t l, h; } b;
uint16_t w;
};
PAIR ax;
您现在可以访问指向& ax.w,& ax.b.l或& ax.b.h等部分的指针 请注意,这仍然不允许您指向单个位,请参阅之前的解释。
编辑:修复示例