Why are bit fields not allowed with normal variables?

I wonder why bit fields work with union / structs, but not with a normal variable of type int or short .
It works:

 struct foo { int bar : 10; }; 

But this fails:

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

Why is this function available only in union / structs and not with variables? Isn't it technically the same?


Edit:

If you will be allowed to make a variable with 3 bytes, for example, without using a struct / union member each time. This is how I would like to create a structure with it:

 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; 
+4
source share
5 answers

This is a subjective question: "Why does the specification say this?" But I will give him my chance.

Variables in functions usually have "automatic" storage, unlike one of the other durations (static duration, stream duration, and assigned duration).

In the structure, you explicitly define the memory layout of an object. But in a function, the compiler automatically allocates storage in some vague way to your variables. Here's the question: how many bytes does x occupy on the stack?

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

It can take up to 4 bytes, or it can take 8 or 12 or 0, or it can be pushed into three different registers at the same time, or on the stack and in the register, or it can get four places on the stack.

The fact is that the compiler performs the allocation for you. Since you are not stacking, you should not specify the width of the bits.

Expanded Discussion: Battlefields are actually a bit special. The specification states that adjacent bit fields are packed into the same memory block. Battle objects are not really objects.

  • You cannot sizeof() a bit field.

  • You cannot malloc() bit field.

  • You cannot &addressof the bit field.

You can do all these things with objects in C, but not with bit fields. Beatps are a special thing, created only for structures and nowhere else.

About int24_t (updated): It works with some architectures, but not with others. It is not even tolerated.

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

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

Note that the GCC code created to load int24_t is basically equivalent to this:

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

These are 9 x64 instructions, just for loading a single value.

+7
source

Members of a structure or union have a relationship between their place of storage. The compiler cannot reorder or pack them in smart ways to save space due to strict layout restrictions; basically, the only freedom that the compiler creates in creating structures is the freedom to add additional additions beyond the amount needed for alignment. The battlefield allows you to manually provide the compiler with more information for packing information, promising that (1) you do not need the address of these members, and (2) you do not need to store values ​​outside a certain limited range.

If you are talking about individual variables, not members of a structure, in an abstract machine they have no relationship between storage locations. If they are local automatic variables in a function and their addresses are never accepted, the compiler can store them in registers or pack them in memory, but they like it. It would be little or not at all useful to use such hints for the compiler manually.

+3
source

Because it does not make sense. Bitfield declarations are used to share and reorganize bits between struct fields. If you have no members, just one variable that has a constant size (which is determined by the implementation). For example, this contradicts the declaration of char , which is almost certainly 8 bits wide, like one or two bits.

+1
source

If you have a QBLOB structure that contains the combined four bits of bit-by-bit into one byte, each time this structure is used, it will be a three-byte saving compared to a structure that simply contained four fields of type unsigned char . If you declare a QBLOB myArray[1000000] array QBLOB myArray[1000000] , such an array will occupy only 1,000,000 bytes; if QBLOB was a four-field unsigned char structure, this would require another 3,000,000 bytes. Thus, the ability to use bit fields can represent a large memory savings.

Unlike most architectures, declaring a simple variable with a bipolar type of optimal size can save no more than 15 bits compared to declaring it the smallest suitable standard integral type. Since access to bit fields usually requires more code than access to variables of standard integral types, there are few cases where declaring individual variables as bit fields will have any advantage.

There is one notable exception to this principle: some architectures include functions that can set, clear, and test individual bits more efficiently than they can read and write bytes. Compilers for some of these architectures include the bit type and will package eight variables of this type in each byte of storage. Such variables are often limited to a static or global scope, since specialized instructions that process them can be limited to using specific areas of memory (the linker can ensure that such variables go where they need to go).

0
source

All objects must occupy one or more adjacent bytes or words, but the bitfield is not an object; it's just a convenient way to mask bits in one word. struct containing a bit-bit must occupy an integer number of bytes or words; the compiler simply adds the necessary addition in case the bitfield sizes do not add up to a full word.

There are no technical reasons why you could not extend the C syntax for defining bit fields outside the structure (AFAIK), but they would be dubious utility for the amount of work.

0
source

All Articles