访问C中的位域

时间:2012-06-20 14:30:38

标签: c bit-fields powerpc

我有一个与硬件中的寄存器对应的结构。

typedef unsigned int uint32;
typedef union A_u{
    uint32 words[4];
    struct {

        uint32 a : 2;
        uint32 b : 3;
        uint32 unused : 27;

        uint32 c : 2;
        uint32 d : 3;
        uint32 unused0 : 27;

        uint32 unused1 : 1;
        uint32 e : 1;
        uint32 f : 1;
        uint32 g : 1;
        uint32 h : 1;
        uint32 i : 1;
        uint32 unused2 : 26;

        uint32 reserved6 : 32;
       }s;
}A_t;

main()
{

    A_t obj;
    uint32 val = 1;

    memset(&obj, 0, sizeof(A_t));
    //fills data
    read_data(&obj);

    printf("0x%x\n", obj.words[2]);
    printf("obj.s.h = %d\n", obj.s.h);

}

输出

  

0x80000000的
  obj.s.h = 1。

虽然第3个字是0x80000000,但obj.s.h显示为1.我无法理解这一点。 我在powerpc上运行它,其中第一位字段是最高位。

1 个答案:

答案 0 :(得分:4)

编译器可以自由地做他们喜欢的事情,直到内存位置如何与结构和联合的成员以及其他复杂的数据结构对齐。

我看到使用由于对齐边界问题引起的结构的神秘运行时错误,因为源的一部分以一种方式看到结构而另一部分以不同的方式看到结构。

C基本上使用结构作为模板来覆盖内存区域,如果不同的文件以不同的方式查看结构,则一段代码计算的结构成员的地址偏移量与另一个不同。

某些编译器将提供一个pragma,允许您指定pack操作,以便您可以指定struct成员的对齐边界。

为了保持与硬件的兼容性,最好的方法似乎是使用无符号字符数组,因为这样你就可以索引无符号字符数组元素,然后用位运算符选择八位之一。然后,您可以将无符号字符数组包装在各种访问函数,类,宏等中,以处理您想要读取和写入的实际数据。使用无符号字符数组也可以更加轻松。

比特字段似乎更像是一种应用程序以更节省内存的方式维护指示符和标志的方式,但对于与应用程序之外的实体(硬件或软件)的通信并不那么有用。根据编译器和运行应用程序的硬件,使用位字段可能会导致运行时间损失,因为位字段被访问,打包和解压缩。