结构体中的位(bit)是否有保证?

3

我有一个与结构体位域相关的问题,请看下面的内容,因为我对应该使用哪些关键字来最好地描述我的问题有点困惑:

背景:我正在编写用于MIPS R3000A汇编指令的反汇编器,这是早期2000年代用于Playstation程序的指令。

问题:我想知道在这段代码中是否有:

struct Instruction {
    u32 other:26;
    u32 op:6;
};

//main:
Instruction instruction = *(Instruction*)(data + pc);
printf("%02x\n", instruction.op);

保证所有使用小端序的编译器始终使用op:6位域来存储前6个最高有效位?(这有点违反直觉,你可能会认为最后6位被存储在op位字段中)

它是以下代码的替代品:

static uint32_t get_op_code(uint32_t data) {
    uint16_t mask = (1 << 6) - 1;
    return (data >> 26) & mask;
}

//main:
uint32_t instruction = *(uint32_t*)(data + pc);
uint32_t op = get_op_code(instruction);
printf("%02x\n", op);

在我的这边运行良好,使用结构化方法似乎要快一些,而且更加直观和清晰,但我担心无法保证前6位被存储在结构体第二个位域“op”中。

1个回答

4
C语言标准不保证位域的排列方式。它要求每个实现定义它,因此应该在编译器的文档中说明。根据C 2018 6.7.2.1 11:
- 实现可以分配足够大的可寻址存储单元来容纳位域。 - 如果有足够的空间,立即跟在结构中另一个位域后面的位域将被打包进同一单元的相邻位中。 - 如果剩余空间不足,则未能适合的位域是放入下一个单元还是重叠相邻的单元,这是由实现来定义的。 - 在单元内分配位域的顺序(从高位到低位或从低位到高位)由实现定义。可寻址存储单元的对齐方式未指定。

好的,谢谢。我正要回答自己的问题,但是我找到了这个:“单元内位域的分配顺序(从高位到低位或从低位到高位)是由实现定义的。” http://c0x.coding-guidelines.com/6.7.2.1.html我会给你点赞的 ;) 不是更多的6.7.2.1 12回答了这个问题吗?另外,为什么你会建议这样做呢?可能保持第二种方法? - Antonin GAVREL
1
@AntoninGAVREL:是的,如果你需要保证 C 中位域的顺序,你必须使用按位运算符而不是位域。然而,许多编译器提供预处理器宏来指示版本和特性,因此另一种方法是编写预处理语句来测试是否正在使用已知的编译器和位域排序。然后,代码可以有条件地编译以定义结构的一个或另一个顺序(如果它识别出正在使用的编译器),或者使用 #error 发出消息(如果它无法识别编译器)。 - Eric Postpischil
嗨@Eric,如果你有时间,能否展示一下你的建议的快速、极简示例? - Antonin GAVREL
@AntoninGAVREL:我手头没有有关GCC或其他编译器在预处理器宏中指示位字段顺序的信息。GCC文档表示,这取决于ABI,因此可能需要测试暗示使用哪个ABI的预处理器宏,或者可能存在直接的预处理器宏来报告顺序,或者可能不存在。您可以在Stack Overflow上提出另一个问题来了解更多信息。 - Eric Postpischil

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接