在MSVC中强制进行未对齐的位域打包

14

我有一个位域结构体,其大小加起来为48位。在GCC上,这将得到正确的6字节结构,但在MSVC中,该结构却变成了8字节。我需要找到一种方法来强制MSVC正确地打包这个结构,既是为了互操作性,也是因为它被用于内存关键的环境中。

下面的结构体由三个15位数字、一个2位数字和一个1位符号组成。15+15+15+2+1=48,所以理论上应该可以放入六个字节中,对吧?

struct S
{
  unsigned short a:15;
  unsigned short b:15;
  unsigned short c:15;
  unsigned short d:2;
  unsigned short e:1;       
};

然而,在GCC和MSVC上编译此代码,sizeof(S) == 8。考虑到这可能与对齐有关,我尝试在结构声明前使用#pragma pack(1)来告诉编译器按字节而不是int边界进行对齐。在GCC上,这行得通了,导致 sizeof(S) == 6

然而,在MSVC05上,即使设置了pack(1)sizeof仍然为8!在阅读此条Stack Overflow答案后,我尝试将unsigned short d替换为unsigned char,并将unsigned short e替换为bool。结果是sizeof(S) == 7

我发现如果我将d拆分成两个一位字段,并将它们插入到其他成员之间,该结构最终可以正确打包。

struct S
{
  unsigned short a:15;
  unsigned short dHi : 1;
  unsigned short b:15;
  unsigned short dLo : 1;
  unsigned short c:15;
  unsigned short e:1;       
};

printf( "%d\n", sizeof(S) ); // "6"

但是像这样分割d很麻烦,并且会在以后处理结构时给我带来麻烦。有没有办法可以强制MSVC将此结构打包为6个字节,就像GCC一样?

3个回答

5

如何在结构体中放置字段是由具体实现定义的。如果可以,Visual Studio将连续的位域放入底层类型中,并浪费剩余空间。(在VS中使用C++位域


非常好的参考!帮我解决了我的问题(VC++一直将我的16位位域转换成4字节结构..现在我知道原因了)。 - nirbruner

5
如果您使用“unsigned __int64”类型来声明结构的所有元素,您将获得一个大小为8的对象,但是最后两个字节将不被使用,前六个字节将包含您想要的格式的数据。
或者,如果您可以接受一些结构重新排序,这也可以实现。
#pragma pack(1)
struct S3
{
  unsigned int a:15;
  unsigned int b:15;
  unsigned int d:2;
  unsigned short c:15;
  unsigned short e:1;       
};

0

我认为不是这样的,我认为MSVC的行为实际上是正确的,而GCC偏离了标准。

据我所知,标准不允许位域跨越底层类型的字边界。


3
注: 有些机器上,位字段跨越分配单元,而在其他机器上则不是这样。 - Tony Delroy

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