4

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

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.sh = 1。

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

4

1 回答 1

4

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

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

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

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

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

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

于 2012-06-20T15:44:05.520 回答