C中的重叠位域

lby*_*san 4 c struct unions bit-fields

我是计算机科学专业的学生。

现在,我正在用C进行计算机架构项目,该项目可模拟处理器。

有很多类型的指令,例如

 31     27 26     22 21     17 16                              0
 ---------------------------------------------------------------
|    op   |    ra   |    rb   |             imm17               |
 ---------------------------------------------------------------

 31     27 26     22 21     17 16                7 6 5 4       0
 ---------------------------------------------------------------
|    op   |    ra   |    rb   |       imm10       | m |  shamt  |
 ---------------------------------------------------------------

 31     27 26     22 21                                        0
 ---------------------------------------------------------------
|    op   |    ra   |                  imm22                    |
 ---------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)

因此,我想制作一个C结构,其中包含与每个元素(例如op,ra等)相对应的位域。

起初,我认为我可以使用联合和嵌套结构。

例如,我编写了如下代码:

struct instr_t {
    union {
        uint32_t imm22 : 22;

        struct {
            union {
                uint32_t imm17: 17;
                struct {
                    uint8_t shamt: 5;
                    uint8_t mode : 2;
                    uint16_t imm10 : 10;
                };
            };
            uint8_t rb : 5;
        };
    };

    uint8_t ra : 5;
    uint8_t op : 5;
}
Run Code Online (Sandbox Code Playgroud)

我期望sizeof(struct instr_t)的结果为4,但实际为12。

嵌套的结构也许有一些填充。

所以,这是我的要求:

如何实现重叠的C位字段?

要么

是否有人可以推荐一种更好的方法来在C中实现多种类型的指令?

谢谢!

Max*_*kin 5

位域成员必须存储在相同的存储单元中,以进行连续布局:

struct instr_1_t {
    uint32_t imm22 : 17;
    uint32_t rb : 5;
    uint32_t ra : 5;
    uint32_t op : 5;
};

struct instr_2_t {
    uint32_t shamt: 5;
    uint32_t m: 2;
    uint32_t imm10 : 10;
    uint32_t rb : 5;
    uint32_t ra : 5;
    uint32_t op : 5;
};

struct instr_3_t {
    uint32_t imm22 : 22;
    uint32_t ra : 5;
    uint32_t op : 5;
};

union instr_t {
    struct {
        uint32_t pad : 22;
        uint32_t op : 5;
    };
    instr_1_t instr_1;
    instr_2_t instr_2;
    instr_3_t instr_3;
};

static_assert(sizeof(instr_t) == sizeof(uint32_t), "sizeof(instr_t) != sizeof(uint32_t)");

void handle_instr(instr_t i) {
    switch(i.op) {
        //
    }
}
Run Code Online (Sandbox Code Playgroud)


VAn*_*rei 5

马克西姆给出了正确答案。

我还建议查看此代码以了解为什么 sizeof instr_t 给出 12 :)

typedef struct s1{
    uint8_t shamt: 5;
    uint8_t mode : 2;
    uint16_t imm10 : 10;
} s_1;

typedef union u1{
    uint32_t imm17: 17;
    s_1 member0;
} u_1;

typedef struct s2{
    u_1 member1;
    uint8_t rb : 5;
} s_2;

typedef union u2{
    uint32_t imm22 : 22;
    s_2 member3;
} u_2;

typedef struct instr_t {
    u_2 member4;
    uint8_t ra : 5;
    uint8_t op : 5;
} s_instr;

int main(int argc, char* argv[])
{
    printf("sizes s_1=%d, u_1=%d, s_2=%d, u_2=%d, s_instr=%d\n", sizeof(s_1), sizeof(u_1), sizeof(s_2), sizeof(u_2), sizeof(s_instr)); 
    printf("uint8_t=%d, uint16_t=%d, uint32_t=%d\n", sizeof(uint8_t), sizeof(uint16_t), sizeof(uint32_t));
    printf("Sizeof instr_t is %d\n", sizeof(s_instr));
}
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助!

干杯!