简体   繁体   English

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

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

I wonder why bitfields work with unions/structs but not with a normal variable like int or short .我想知道为什么位域适用于联合/结构,而不适用于像intshort这样的普通变量。
This works:这有效:

struct foo {
    int bar : 10;
};

But this fails:但这失败了:

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

Why is this feature only available in unions/structs and not with variables?为什么此功能仅在联合/结构中可用,而在变量中不可用? Isn't it technical the same?技术上不一样吗?


Edit:编辑:

If it would be allowed you could make a variable with 3 bytes for instance without using the struct/union member each time.如果允许,您可以创建一个具有 3 个字节的变量,而无需每次都使用 struct/union 成员。 This is how I would to it with a struct:这就是我对结构的处理方式:

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;

This is a subjective question, "Why does the spec say this?"这是一个主观问题,“为什么规范这么说?” But I'll give it my shot.但我会尽力而为。

Variables in a function normally have "automatic" storage, as opposed to one of the other durations (static duration, thread duration, and allocated duration).函数中的变量通常具有“自动”存储,而不是其他持续时间之一(静态持续时间、线程持续时间和分配的持续时间)。

In a struct, you are explicitly defining the memory layout of some object.在结构中,您明确定义了某个对象的内存布局。 But in a function, the compiler automatically allocates storage in some unspecified manner to your variables.但是在函数中,编译器会以某种未指定的方式自动为变量分配存储空间。 Here's a question: how many bytes does x take up on the stack?这里有一个问题: x在堆栈上占用了多少字节?

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

It could take up 4 bytes, or it could take up 8, or 12, or 0, or it could get placed in three different registers at the same time, or the stack and a register, or it could get four places on the stack.它可能占用 4 个字节,也可能占用 8 个、12 个或 0 个字节,或者它可以同时放置在三个不同的寄存器中,或者堆栈和一个寄存器中,或者它可以在堆栈上放置四个位置.

The point is that the compiler is doing the allocation for you.关键是编译器正在为您进行分配。 Since you are not doing the layout of the stack, you should not specify the bit widths.由于您没有进行堆栈的布局,因此不应指定位宽。

Extended discussion: Bitfields are actually a bit special.扩展讨论:位域实际上有点特殊。 The spec states that adjacent bitfields get packed into the same storage unit.该规范指出相邻的位域被打包到同一个存储单元中。 Bitfields are not actually objects.位域实际上不是对象。

  1. You cannot sizeof() a bit field.你不能sizeof()一个位域。

  2. You cannot malloc() a bit field.你不能malloc()一个位域。

  3. You cannot &addressof a bit field.你不能&addressof位域。

All of these things you can do with objects in C, but not with bitfields.所有这些事情你都可以用 C 中的对象来做,但不能用位域来做。 Bitfields are a special thing made just for structures and nowhere else.位域是一种特殊的东西,只为结构而生,没有其他地方。

About int24_t (updated): It works on some architectures, but not others.关于int24_t (更新):它适用于某些架构,但不适用于其他架构。 It is not even slightly portable.它甚至没有一点便携性。

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

On Linux ELF/x64, OS X/x86, OS X/x64, sizeof(int24_t) == 3 .在 Linux ELF/x64、OS X/x86、OS X/x64 上, sizeof(int24_t) == 3 But on OS X/PowerPC, sizeof(int24_t) == 4 .但在 OS X/PowerPC 上, sizeof(int24_t) == 4

Note the code GCC generates for loading int24_t is basically equivalent to this:请注意,GCC 为加载int24_t生成的代码基本上等同于:

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

It's 9 instructions on x64, just to load a single value.这是 x64 上的 9 条指令,只是为了加载单个值。

Members of a structure or union have relationships between their storage location.结构或联合的成员在其存储位置之间存在关系。 A compiler cannot reorder or pack them in clever ways to save space due to strict constraints on the layout;由于对布局的严格限制,编译器无法以巧妙的方式重新排序或打包它们以节省空间; basically the only freedom a compiler has in laying out structures is the freedom to add extra padding beyond the amount that's needed for alignment.基本上,编译器在布局结构方面的唯一自由是添加超出对齐所需数量的额外填充的自由。 Bitfields allow you to manually give the compiler more freedom to pack information tightly by promising that (1) you don't need the address of these members, and (2) you don't need to store values outside a certain limited range.位域允许您通过承诺 (1) 您不需要这些成员的地址,以及 (2) 您不需要存储某个有限范围之外的值,从而手动给予编译器更多的自由来紧密地打包信息。

If you're talking about individual variables rather than structure members, in the abstract machine they have no relationship between their storage locations.如果您谈论的是单个变量而不是结构成员,那么在抽象机器中,它们的存储位置之间没有关系 If they're local automatic variables in a function and their addresses are never taken, the compiler is free to keep them in registers or pack them in memory however it likes.如果它们是函数中的局部自动变量并且它们的地址永远不会被占用,那么编译器可以随意将它们保存在寄存器中或将它们打包在内存中。 There would be little or no benefit to providing such hints to the compiler manually.手动向编译器提供此类提示几乎没有好处。

Because it's not meaningful.因为意义不大。 Bitfield declarations are used to share and reorganize bits between fields of a struct .位域声明用于在struct字段之间共享和重新组织位。 If you have no members, just a single variable, that is of constant size (which is implementation-defined), For example, it's a contradiction to declare a char , which is almost certainly 8 bits wide, as a one or twelwe bit variable.如果您没有成员,只有一个大小恒定的变量(这是实现定义的),例如,将几乎肯定为 8 位宽的char声明为 1 位或 12 位变量是矛盾的.

If one has a struct QBLOB which contains combines four 2-bit bitfields into a single byte, every time that struct is used will represent a savings of three bytes as compared with a struct that simply contained four fields of type unsigned char .如果一个结构QBLOB包含将四个 2 位位域组合成一个字节,则每次使用该结构时,与仅包含四个unsigned char类型字段的结构相比,每次使用该结构都将节省三个字节。 If one declares an array QBLOB myArray[1000000] , such an array will take only 1,000,000 bytes;如果声明一个数组QBLOB myArray[1000000] ,这样的数组将只占用 1,000,000 个字节; if QBLOB had been a struct with four unsigned char fields, it would have needed 3,000,000 bytes more.如果 QBLOB 是一个具有四个unsigned char字段的结构,它将需要多 3,000,000 个字节。 Thus, the ability to use bitfields may represent a big memory savings.因此,使用位域的能力可以代表大量的内存节省。

By contrast, on most architectures, declaring a simple variable to be of an optimally-sized bitfield type could save at most 15 bits as compared with declaring it to be the smallest suitable standard integral type.相比之下,在大多数体系结构上,将简单变量声明为最佳大小的位域类型与将其声明为最小的合适标准整数类型相比,最多可以节省 15 位。 Since accessing bitfields generally requires more code than accessing variables of standard integral types, there are few cases where declaring individual variables as bit fields would offer any advantage.由于访问位域通常比访问标准整数类型的变量需要更多的代码,因此很少有将单个变量声明为位域会带来任何好处的情况。

There is one notable exception to this principle, though: some architectures include features which can set, clear, and test individual bits even more efficiently than they can read and write bytes.不过,这一原则有一个值得注意的例外:某些架构包含的功能可以比读写字节更有效地设置、清除和测试单个位。 Compilers for some such architectures include a bit type, and will pack eight variables of that type into each byte of of storage.某些此类架构的编译器包含bit类型,并将该类型的八个变量打包到存储的每个字节中。 Such variables are often restricted to static or global scope, since the specialized instructions that handle them may be restricted to using certain areas of memory (the linker can ensure any such variables get placed where they have to go).此类变量通常仅限于静态或全局范围,因为处理它们的专用指令可能仅限于使用某些内存区域(链接器可以确保将任何此类变量放置在它们必须去的地方)。

All objects must occupy one or more contiguous bytes or words, but a bitfield is not an object ;所有对象必须占用一个或多个连续的字节或字,但位域不是对象 it's simply a user-friendly way of masking out bits in a word.它只是一种用户友好的方式来屏蔽单词中的位。 The struct containing the bitfield must occupy a whole number of bytes or words;包含位域的struct必须占用整数个字节或字; the compiler just adds the necessary padding in case the bitfield sizes don't add up to a full word.编译器只是添加了必要的填充,以防位域大小加起来不是一个完整的字。

There's no technical reason why you couldn't extend C syntax to define bitfields outside of a struct (AFAIK), but they'd be of questionable utility for the amount of work involved.没有技术原因不能扩展 C 语法来定义结构(AFAIK)之外的位域,但是对于所涉及的工作量,它们的实用性值得怀疑。

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

相关问题 为什么我不能将位域声明为自动变量? - Why can't I declare bitfields as automatic variables? 为什么我们不允许在切换情况下甚至使用全局const限定变量?IBM支持门户网站提示我们可以 - Why aren't we allowed to use even global const qualified variables in switch-case?IBM support portal hints we can 为什么C变量的内存地址不固定? - Why aren't memory addresses of C variables fixed? 为什么在增加的内存位置中没有连续定义的变量? - Why aren't consecutively-defined variables in increasing memory locations? 为什么在WaitForSingleObject之后我的变量不保持状态? - Why aren't my variables holding state after WaitForSingleObject? 为什么这个不允许编译器执行的示例使用cmov导致空指针取消引用? - Why does this example of what compilers aren't allowed to do cause null pointer dereferencing using cmov? 为什么位域必须是整数? - Why bitfields have to be integer? Bitfields,为什么具体实现? - Bitfields, why implementation specific? 为什么不保存我的变量? 我一直在测试此代码,但我的变量未保存到结构数组中 - Why aren't my variables being saved? I've been testing this code and my variables aren't being saved into my struct array 为什么gcc(ARM)不使用全局寄存器变量作为源操作数? - Why gcc (ARM) aren't using Global Register Variables as source operands?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM