繁体   English   中英

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

[英]Why aren't bitfields allowed with normal variables?

我想知道为什么位域适用于联合/结构,而不适用于像intshort这样的普通变量。
这有效:

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;

这是一个主观问题,“为什么规范这么说?” 但我会尽力而为。

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

在结构中,您明确定义了某个对象的内存布局。 但是在函数中,编译器会以某种未指定的方式自动为变量分配存储空间。 这里有一个问题: 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 条指令,只是为了加载单个值。

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

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

因为意义不大。 位域声明用于在struct字段之间共享和重新组织位。 如果您没有成员,只有一个大小恒定的变量(这是实现定义的),例如,将几乎肯定为 8 位宽的char声明为 1 位或 12 位变量是矛盾的.

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

相比之下,在大多数体系结构上,将简单变量声明为最佳大小的位域类型与将其声明为最小的合适标准整数类型相比,最多可以节省 15 位。 由于访问位域通常比访问标准整数类型的变量需要更多的代码,因此很少有将单个变量声明为位域会带来任何好处的情况。

不过,这一原则有一个值得注意的例外:某些架构包含的功能可以比读写字节更有效地设置、清除和测试单个位。 某些此类架构的编译器包含bit类型,并将该类型的八个变量打包到存储的每个字节中。 此类变量通常仅限于静态或全局范围,因为处理它们的专用指令可能仅限于使用某些内存区域(链接器可以确保将任何此类变量放置在它们必须去的地方)。

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

没有技术原因不能扩展 C 语法来定义结构(AFAIK)之外的位域,但是对于所涉及的工作量,它们的实用性值得怀疑。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM