17

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

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

这是代码...

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;
}
4

5 回答 5

36

位域成员(通常)小于指针所允许的粒度,即chars 的粒度(根据 的定义char顺便说一句,它被要求至少为 8 位长)。因此,常规指针不会削减它。

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

最后,它几乎不是一个要求的功能(位域在第一时间并不常见);位域用于紧凑地存储信息或构建标志的打包表示(例如写入硬件端口),您很少需要指向它们的单个字段的指针 - 如果需要,您总是可以诉诸常规struct并在最后一刻转换为位域。

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

于 2012-11-25T01:17:57.003 回答
8

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

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

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

一元运算&符的操作数应该是函数指示符、a []或一元运算*符的结果,或者lvalue指定不是位域且未使用寄存器存储类说明符声明的对象的 an。

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

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

您可以看到所有这些位文件的地址实际上是相同的,所以它并没有那么有用。

对于操作位文件,您真的应该直接访问它们并让编译器对其进行排序。除非您知道编译器如何将它们布置在内存中,否则即使使用按位运算符也不能保证有效。

于 2012-11-25T01:13:59.403 回答
5

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

于 2012-11-25T01:15:43.540 回答
0

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

无符号整数 x=pipe.a; printf("x=%d",&x);

于 2019-05-31T01:34:52.140 回答
-1

在类似的注释中,如果您只想处理单个字节,您可以执行以下操作:

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

PAIR ax;

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

编辑:固定示例

于 2015-07-07T13:31:16.303 回答