无法获取位域地址

问题描述 投票:0回答:5

为什么不能取位域地址?

如何创建指向位域的指针?

这是代码...

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;
}
c pointers syntax-error bit-fields memory-address
5个回答
43
投票

Bitfields 成员(通常)小于指针允许的粒度,即

char
的粒度(通过 char
definition
,顺便说一下,它的长度至少为 8 位)。所以,普通的指针并不能解决这个问题。

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

最后,这几乎不是一个被请求的功能(位域首先并不常见);位字段用于紧凑地存储信息或构建标志的打包表示(例如写入硬件端口),您很少需要指向其中的“单个字段”的指针 - 如果需要,您始终可以求助于常规 struct 并在最后一刻转换为位字段。


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

您实际上无法拥有

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

10
投票
您所希望的最好结果是包含字节集的地址。

标准的相关部分(本例中为 C11)是第 6.5.3.2 Address and indirection operators

节(我的重点):

一元

&
运算符的操作数应为函数指示符、

[]
或一元

*

 运算符的结果,或者指定 
 不是位域
的对象的
lvalue
 并且未使用寄存器存储类说明符进行声明。
鉴于寻址单位是字节,您可能会发现位字段存储为(例如): Bit 7 6 5 4 3 2 1 0 +---+---+---+---+---+---+---+---+ Address: 1234 | a | b | c | d | ? | ? | ? | ? | +---+---+---+---+---+---+---+---+ 1235 | | | | | | | | | +---+---+---+---+---+---+---+---+

你可以看到所有这些位域的地址实际上是相同的(1234),所以区分它们并不是很有用..

对于操作位字段,您确实应该直接访问它们并让编译器对其进行排序。
即使使用按位运算符也不能保证有效,除非你

知道

编译器如何将它们布置在内存中。

地址必须是整数字节,但位字段不必如此,因此 C 标准指定

地址运算符

6
投票
不能与它们一起使用。当然,如果您确实想使用位域的地址进行操作,则可以仅使用封闭结构的地址,并进行一些按位运算。

您无法打印位字段的地址,但您可以分配给所需大小类型的某些局部变量(从一位内存类型转换为2字节(对于整数类型大小将取决于编译器)内存),可以使用用于打印地址。

unsigned int x=pipe.a; printf("x=%d",&x);

0
投票

类似地,如果您只想寻址单个字节,您可以这样做:

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

-1
投票
您现在可以访问指向 &ax.w、&ax.b.l 或 &ax.b.h 等片段的指针 请注意,这仍然不允许您指向各个位,请参阅之前的解释。

编辑:固定示例
    

© www.soinside.com 2019 - 2024. All rights reserved.