访问 C 语言中的位域



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

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%xn", obj.words[2]);
    printf("obj.s.h = %dn", obj.s.h);
}

输出为


0x80000000 obj.s.h = 1。

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

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

我见过使用结构的神秘运行时错误,这些错误是由于对齐边界问题造成的,因为源的一部分以一种方式看到结构,而另一部分以不同的方式看到它。

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

某些编译器将提供一个杂注,允许您指定包操作,以便您可以指定结构成员的对齐边界。

为了保持与硬件的兼容性,最好的办法似乎是使用无符号字符数组,因为这样您就可以索引到无符号字符数组元素,然后使用按位运算符选择八个位之一。 然后,您可以将无符号字符数组包装在各种访问函数、类、宏等中,以操作要读取和写入的实际数据。 使用无符号字符数组往往也更具可移植性。

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

最新更新