c - 不能取位域的地址

时间:2012-11-25 01:08:57

标签: c pointers syntax-error bit-fields memory-address

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

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

以下是代码......

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

5 个答案:

答案 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等部分的指针 请注意,这仍然不允许您指向单个位,请参阅之前的解释。

编辑:修复示例