为什么相同数据类型的位域比混合数据类型的位域更小?

6

我很好奇为什么使用相同数据类型的位域比使用混合数据类型的位域占用更少的空间。

struct xyz 
{ 
  int x : 1; 
  int y : 1; 
  int z : 1; 
}; 


struct abc 
{ 
  char x : 1; 
  int y : 1; 
  bool z : 1; 
}; 

xyz的大小为4,abc的大小为12。

我正在使用VS 2005,64位x86机器。

如果能提供位级别或编译器级别的答案会更好。

3个回答

5

对齐。

编译器将按照适合您的架构的方式对变量进行对齐。在您的情况下,charintbool的大小不同,因此它将根据这些信息而不是您的位域提示进行对齐。

这个问题中有关于此事的讨论。

解决方案是给您的编译器提供#pragma指令或__attributes__以指示其忽略对齐优化。


1
请注意,位域实际上没有对齐要求。 - user25148
不,但编译器没有义务对它们进行打包。 - greyfade
请参阅ISO14882:2003,§9.6,第1段。 - greyfade
2
学习机器体系结构和编译器构建的另一个原因,尽管一些人在SO上否认,但仍对程序员有用。 - Craig S

3
C标准(1999版,§6.7.2.1,第102页,第10点)如下所述:
实现可以分配任何足以容纳位域的可寻址存储单元。如果剩余空间足够,则跟随结构中另一个位域的位域应打包到同一单元的相邻位中。
似乎没有任何措辞允许字段类型影响打包。因此,我会得出这是编译器错误的结论。
在Linux下,对于32位和64位机器,gcc在两种情况下都创建了4字节的结构。我没有VS,无法测试。

1
C++03,§9.6,第1段说:“类对象内的位域分配是实现定义的。位域对齐是实现定义的。位域被打包到一些可寻址的分配单元中。”看起来Mahesh正在使用C++编译器。 - greyfade
另一方面,他也将这标记为C问题,而不仅仅是C ++。我猜对于C和C ++的答案是不同的。 - user25148
我会谨慎地将这个归为“错误”,因为你引用自ISO C99标准。MSVC++并没有声称遵循C99标准。它支持ISO C90/ANSI C89。 - Clifford
PS:在位域中使用除int或unsigned之外的类型是相对于C89/90的扩展,因此行为方面存在不确定性。 - Clifford
如果MSVC++不支持十年前的标准...这听起来并不令人印象深刻,是吧? - user25148
@ greyfade 引用标准的重要说明。 实际上,msvc似乎总是分配不同类型的第一个变量,而不像gcc和clang。例如:{uint16_t a:14; uint8_t x:2;}对于msvc / gcc / clang将返回sizeof 4/2/2。 - brita_

0

这是编译器的错误还是代码错误。 在结构中分配的所有位始终尝试使sizeof最高数据类型定义。 例如,在struct xyz中,最高数据类型的sizeof为4,即int。 类似地,对于第二个结构abc,int的最高数据类型大小为4。

然而,如果我们将结构的变量更改如下: struct abc { char a:1; char b:1; bool c:1; };

sizeof(abc)将为1而不是4。因为最高数据类型的大小为1,所有位都适合char的1字节中。

可以通过更改结构中的数据类型来执行各种测试。

基于旧结构的输出链接: 访问http://codepad.org/6j5z2CEX

基于我定义的上述结构的输出链接: 访问http://codepad.org/fqF9Ob8W

为了避免这样的sizeof结构问题,我们应该使用#pragma pack宏正确打包结构。


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