C - 为什么#pragma pack(1)将6位结构成员视为8位?

Bat*_*ted 0 c winapi struct pragma-pack

#pragma pack(1)当定义一个6-bit字段并假设它时,我对错误的行为感到困惑8-bit.我读了这个问题来解决我的问题,但它根本没有帮助我.

Visual Studio 2012中,我定义了struct以下保存Base64字符:

#pragma pack(1)
struct BASE64 {
    CHAR    cChar1 : 6;
    CHAR    cChar2 : 6;
    CHAR    cChar3 : 6;
    CHAR    cChar4 : 6;
};
Run Code Online (Sandbox Code Playgroud)

现在我得到它的大小sizeof,但结果不是我的预期:

printf("%d", sizeof(BASE64));      // should print 3
Run Code Online (Sandbox Code Playgroud)

结果: 4

我期待得到3(因为6 * 4 = 24,所以24位是3字节)

事件我用1-bit字段测试它,并得到正确的大小(1字节):

#pragma pack(1)
struct BASE64 {
    CHAR    cChar1 : 2;
    CHAR    cChar2 : 2;
    CHAR    cChar3 : 2;
    CHAR    cChar4 : 2;
};
Run Code Online (Sandbox Code Playgroud)

其实,为什么6-bit假定8-bit#pragma pack(1)

pax*_*blo 6

#pragma pack通常打包在字节边界上,而不是位边界.这是为了防止在要保持压缩的字段之间插入填充字节.来自Microsoft的文档(因为您提供了winapi标记,并且我强调了):

n(可选):指定用于打包的值(以字节为单位).

当您尝试让位字段跨越字节边界时,实现如何处理位字段是实现定义的.从C11标准(第二部分6.7.2.1 Structure and union specifiers /11,我的重点):

实现可以分配足够大的任何可寻址存储单元来保持位域.如果剩余足够的空间,则紧跟在结构中的另一个位字段之后的位字段将被打包到相同单元的相邻位中.如果剩余的空间不足,则是否将不适合的位域放入下一个单元或重叠相邻单元是实现定义的.单元内的位域分配顺序(高阶到低阶或低阶到高阶)是实现定义的.未指定可寻址存储单元的对齐.

更多的MS文档调用了这个特定的行为:

如果整数类型具有相同的大小并且如果下一个比特字段适合当前分配单元而不跨越公共对齐要求所施加的边界,则相邻的比特字段被打包到相同的1字节,2字节或4字节分配单元中位字段.