c - 为什么普通变量不允许位域?

标签 c gcc struct unions bit-fields

我想知道为什么位域与 union/结构一起工作,而不与像 intshort 这样的普通变量一起工作。
这有效:

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个,也可以同时放入三个不同的寄存器,或者栈和一个寄存器,也可以得到四个位置在堆栈上。

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

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

  1. 您不能sizeof() 位域。

  2. 您不能 malloc() 位域。

  3. 您不能&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/

相关文章:

c - 为什么 gcc 和 clang 没有将 strlen 提升到这个循环之外?

c++ - vector 中的 Unique_ptr 作为结构的属性

c - 关于 C 中的指针基础知识

c - 如果我有一个指向结构的指针,我如何访问它的成员之一?

gcc - REGSITER_TM_CLONES 中的 Shift 操作的目的是什么?

c - 帮助 C 程序中的 if-else

C - 未知数字中的最大数字

c++ - 类型 cast char array[16] to int 128 bits

c - a[j++] =++i 的等效表达式,不使用前置或后置增量运算符

c - 如何在 C 中为嵌入式系统定义堆栈地址范围