为什么普通变量不允许使用位域?

我想知道为什么位域与联合/结构一起使用但不能使用像intshort这样的正常变量。
这有效:

 struct foo { int bar : 10; }; 

但这失败了:

 int bar : 10; // "Expected ';' at end of declaration" 

为什么此function仅在联合/结构中可用而不在变量中? 技术不一样吗?


编辑:

如果允许,你可以创建一个3字节的变量,而不是每次都使用struct / union成员。 这就是我对结构的看法:

 struct int24_t { int x : 24 __attribute__((packed)); }; struct int24_t var; // sizeof(var) is now 3 // access the value would be easier: var.x = 123; 

这是一个主观的问题,“为什么规范这样说?” 但是我会试一试。

函数中的变量通常具有“自动”存储,而不是其他持续时间之一(静态持续时间,线程持续时间和分配的持续时间)。

在结构中,您明确定义某个对象的内存布局。 但是在函数中,编译器会自动以某种未指定的方式将存储分配给变量。 这是一个问题: x占用了多少字节?

 // sizeof(unsigned) == 4 unsigned x; 

它可能占用4个字节,或者它可能占用8个,12个或0个,或者它可以同时放在三个不同的寄存器中,或者堆栈和寄存器,或者它可以在堆栈上获得四个位置。

关键是编译器正在为您进行分配。 由于您没有进行堆栈布局,因此不应指定位宽。

扩展讨论: Bitfield实际上有点特殊。 规范声明相邻的位域被打包到同一个存储单元中。 位域实际上不是对象。

  1. 你不能sizeof()一个字段。

  2. 你不能malloc()有点字段。

  3. 你不能&addressof

所有这些都可以用C语言中的对象完成,但不能用位域。 Bitfields是一种特殊的东西,仅用于结构而不是其他任何地方。

关于int24_t (更新):它适用于某些体系结构,但不适用于其他体系结构。 它甚至没有轻微的便携性。

 typedef struct { int x : 24 __attribute__((packed)); } int24_t; 

在Linux ELF / x64,OS X / x86,OS X / x64, sizeof(int24_t) == 3 。 但是在OS X / PowerPC上, sizeof(int24_t) == 4

注意GCC生成的用于加载int24_t的代码基本上等同于:

 int result = (((char *) ptr)[0] << 16) | (((unsigned char *) ptr)[1] << 8) | ((unsigned char *)ptr)[2]; 

这是x64上的9条指令,只是为了加载一个值。

结构或联合的成员在其存储位置之间具有关系。 由于严格的布局限制,编译器无法以巧妙的方式对它们进行重新排序或打包以节省空间; 基本上编译器在布局结构时唯一的自由就是可以自由地添加超出对齐所需量的额外填充。 通过承诺(1)您不需要这些成员的地址,以及(2)您不需要存储超出特定限制范围的值,Bitfields允许您手动为编译器提供更大的自由来紧密打包信息。

如果您在讨论单个变量而不是结构成员,那么在抽象机器中,它们的存储位置之间没有关系 。 如果它们是函数中的本地自动变量并且它们的地址永远不会被占用,则编译器可以自由地将它们保存在寄存器中或者将它们打包在内存中,但它喜欢它们。 手动向编译器提供这样的提示几乎没有或没有好处。

因为它没有意义。 位域声明用于在struct字段之间共享和重组位。 如果你没有成员,只有一个变量,它具有恒定的大小(由实现定义),例如,声明一个char ,几乎可以肯定是8位宽,作为一个或两个比特变量是一个矛盾。

如果一个结构QBLOB包含将四个2位位字段组合成一个字节,那么每次使用该结构时,与仅包含四个unsigned char类型字段的结构相比,将节省三个字节。 如果一个声明一个数组QBLOB myArray[1000000] ,这样的数组将只占用1,000,000个字节; 如果QBLOB是一个带有四个unsigned char字段的结构,那么它将需要3,000,000字节。 因此,使用位域的能力可以代表大量的存储器节省。

相比之下,在大多数体系结构中,将一个简单变量声明为最佳大小的位域类型与声明它是最小的合适标准整数类型相比,最多可以节省15位。 由于访问位域通常需要比访问标准积分类型的变量更多的代码,因此很少有将单个变量声明为位字段可提供任何优势的情况。

但是,这个原则有一个明显的例外:一些架构包括可以设置,清除和测试单个位的function,甚至比读取和写入字节更有效。 某些此类体系结构的编译器包括bit类型,并将该类型的八个变量打包到存储的每个字节中。 此类变量通常仅限于静态或全局范围,因为处理它们的专用指令可能仅限于使用某些内存区域(链接器可以确保将任何此类变量放置在必须放置的位置)。

所有对象必须占用一个或多个连续的字节或单词,但是一个位域不是一个对象 ; 它只是一种用户友好的方式来掩盖单词中的位。 包含位域的struct必须占用整数个字节或字; 编译器只是添加必要的填充,以防位域大小加起来不是一个完整的单词。

没有技术原因可以解释为什么你不能扩展C语法来定义结构(AFAIK)之外的位域,但是它们对于所涉及的工作量来说是有问题的。