我想知道为什么位域可以使用联合/结构但不能使用int
或short
这样的常规变量。
这有效:
struct foo {
int bar : 10;
};
但这失败了:
int bar : 10; // "Expected ';' at end of declaration"
为什么此功能仅在联合/结构中可用而不在变量中?技术不一样吗?
修改
如果允许,你可以创建一个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;
答案 0 :(得分:7)
这是一个主观问题,“为什么规范说这个?”但是我会试一试。
函数中的变量通常具有“自动”存储,而不是其他持续时间(静态持续时间,线程持续时间和分配持续时间)。
在结构中,您明确定义了某个对象的内存布局。但是在函数中,编译器会自动以某种未指定的方式将存储分配给变量。这是一个问题:x
占用了多少字节?
// sizeof(unsigned) == 4
unsigned x;
它可能占用4个字节,或者它可能占用8个,12个或0个,或者它可以同时放在三个不同的寄存器中,或者堆栈和寄存器,或者它可以获得四个位置在堆栈上。
重点是编译器正在为您进行分配。由于您没有进行堆栈布局,因此不应指定位宽。
扩展讨论:Bitfield实际上有点特殊。规范声明相邻的位域被打包到同一个存储单元中。位域实际上不是对象。
你不能sizeof()
位字段。
你不能malloc()
位字段。
你不能&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 :(得分:3)
结构或联合的成员在其存储位置之间存在关系。由于严格的布局约束,编译器无法以巧妙的方式重新排序或打包它们以节省空间;基本上编译器在布局结构时唯一的自由就是可以自由地添加超出对齐所需量的额外填充。通过承诺(1)您不需要这些成员的地址,以及(2)您不需要存储值,Bitfields允许您手动为编译器提供更大的自由来紧密打包信息超出一定的范围。
如果您正在讨论单个变量而不是结构成员,那么在抽象机器中,它们的存储位置之间存在无关系。如果它们是函数中的本地自动变量并且它们的地址永远不会被占用,则编译器可以自由地将它们保存在寄存器中或者将它们打包在内存中但是它喜欢它们。手动向编译器提供此类提示几乎没有任何益处。
答案 2 :(得分:1)
因为它没有意义。位域声明用于共享和重新组织struct
的字段之间的位。如果你没有成员,只有一个变量,它具有恒定的大小(由实现定义),例如,声明一个char
(几乎可以肯定是8位宽)是一个矛盾的矛盾。或者twelwe位变量。
答案 3 :(得分:0)
如果一个结构QBLOB
包含将四个2位位域组合成一个字节,那么每次使用该结构时,与仅包含四个字段的结构相比,将节省三个字节。输入unsigned char
。如果一个声明一个数组QBLOB myArray[1000000]
,这样的数组将只占用1,000,000个字节;如果QBLOB是一个包含四个unsigned char
字段的结构,那么它将需要3,000,000字节。因此,使用位域的能力可以节省大量内存。
相比之下,在大多数体系结构中,声明一个简单变量为最佳大小的位域类型,与声明它是最小的合适标准整数类型相比,最多可以节省15位。由于访问位域通常需要比访问标准整数类型变量更多的代码,因此很少有将单个变量声明为位字段可以提供任何优势的情况。
但是,这个原则有一个值得注意的例外:一些架构包括可以设置,清除和测试单个位的功能,甚至比读取和写入字节更有效。某些此类体系结构的编译器包含bit
类型,并将该类型的八个变量打包到存储的每个字节中。这些变量通常仅限于静态或全局范围,因为处理它们的专用指令可能仅限于使用某些内存区域(链接器可以确保将任何此类变量放置在必须放置的位置)。
答案 4 :(得分:0)
所有对象必须占用一个或多个连续的字节或单词,但是一个位域不是对象;它只是一种用户友好的方式来掩盖单词中的位。包含位域的struct
必须占用整数个字节或字;编译器只是添加必要的填充,以防位域大小加起来不是一个完整的单词。
没有技术的原因,你无法扩展C语法来定义结构(AFAIK)之外的位域,但它们对于所涉及的工作量来说是有问题的。