我想知道为什么位域与 union/结构一起工作,而不与像 int
或 short
这样的普通变量一起工作。
这有效:
struct foo {
int bar : 10;
};
但这失败了:
int bar : 10; // "Expected ';' at end of declaration"
为什么此功能仅适用于 union/结构而不适用于变量?技术上不一样吗?
编辑:
如果允许的话,你可以创建一个 3 字节的变量,而不必每次都使用结构/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个,也可以同时放入三个不同的寄存器,或者栈和一个寄存器,也可以得到四个位置在堆栈上。
重点是编译器正在为您进行分配。由于您没有进行堆栈布局,因此不应指定位宽。
扩展讨论: 位域实际上有点特殊。规范指出相邻的位域被打包到同一个存储单元中。位域实际上不是对象。
您不能
sizeof()
位域。您不能
malloc()
位域。您不能
&addressof
位域。
所有这些你都可以用 C 中的对象来做,但不能用位域。位域是一种专为结构而生的特殊东西。
关于 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 条指令,只是为了加载一个值。
关于c - 为什么普通变量不允许位域?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13958464/