int 位域的大小和对齐方式

size and alignment of int bitfields

具有位域的结构,即使在“打包”时,似乎也会根据指定的 int 类型处理位域的大小(以及对齐方式?)。有人可以 指出定义该行为的 C++ 规则吗? 我尝试了十几种编译器和架构(谢谢 Compiler Explorer!),结果在所有方面都是一致的。

下面是要玩的代码: https://godbolt.org/z/31zMcnboY

#include <cstdint>

#pragma pack(push, 1)
struct S1{ uint8_t  v: 1; }; // sizeof == 1
struct S2{ uint16_t v: 1; }; // sizeof == 2
struct S3{ uint32_t v: 1; }; // sizeof == 4
struct S4{ unsigned v: 1; }; // sizeof == 4
#pragma pack(pop)

auto f(auto s){ return sizeof(s); }

int main(){
    f(S1{});
    f(S2{});
    f(S3{});
    f(S4{});
}

生成的 ASM 清楚地显示 f() 返回的大小分别为 S1S2S3 的 1、2、4:

Could someone point to a C++ rule that defines that behavior?

标准没有指定任何关于 #pragma pack(push, 1) 的内容(除了 #pragma 被指定为具有实现定义含义的 pre-processor 指令)。它是一个语言扩展。

这是关于位域的标准规定:

[class.bit]

... A bit-field shall have integral or (possibly cv-qualified) enumeration type; the bit-field semantic property is not part of the type of the class member. ... Allocation of bit-fields within a class object is implementation-defined. Alignment of bit-fields is implementation-defined. Bit-fields are packed into some addressable allocation unit.

基本上完全由实现定义或未指定。

bit-field 序列的最小大小是其基础类型的大小。多个相邻的相同底层类型的 bit-field 被打包到最小数量的底层类型的单词,而不分解任何 bit-field。大小为 0 的 bit-field 表示显式中断,后续字段从下一个单词开始。混合基础类型会导致在分歧点出现突破。位不是大多数机器上的最小可寻址单元,数据类型的大小以八位字节为单位测量,作为最小可寻址内存单元。