Enum and unsigned long bitfields

If I have the following structure with an enum and unsigned length, how is the padding done? I believe the compiler will not do anything with var1

and var2

since it is filled with 32 bits.

typedef struct {
    unsigned long var1 : 8;
    unsigned long var2 : 24;
    my_enum var3       : 2;
    my_enum var4       : 2;
} my_struct;

      

Will there be filling for var3

and var4

? for example, 30 bits of indentation before var3

and 30 bits before var4

, or 28 bits. I'm just trying to understand how bit fields work with different data types and implementation types.

+3


source to share


1 answer


1. Types used in the bit field:

I would only use signed int

or unsigned int

in your structure as a bitfield type. According to the C99 standard (6.7.2.1 # 4):

The bit field must be of a type that is a qualified or unqualified version of _Bool , a signed int , unsigned int, or some other implementation-defined type.

Of course, unsigned long

and enum type

are implementation-defined types, but if you use them the behavior is not portable. You can see this in two different versions of GCC:

According to the manual for gcc 4.8.4 :

  • Valid bitfield types other than _Bool, signed int, and unsigned int (C99 6.7.2.1).

No other types are allowed in strictly compliant mode.

According to the manual for gcc-5.2.0 :

  • Valid bitfield types other than _Bool are signed int and unsigned int (C99 and C11 6.7.2.1).

Other integer types such as long int and enumerated types are allowed even in strictly compliant mode.

2. Upholstery:

Battlefields operate at the word and byte level and cannot cross word boundaries. C99 ensures that bitpoles are packed as tightly as possible as long as they don't cross storage unit boundaries (6.7.2.1 # 10).

An implementation can allocate any address storage unit large enough to store the bit-field. If there is enough space, a bit-field that immediately follows another bit-field in the structure should be packed into adjacent bits of the same block. If there is not enough space, will the bit-field that does not fit fit into the next block, or overlap adjacent implementation units. The order in which the bit-fields are allocated within one (from high to low or low order) is implementation-defined. The storage address block alignment is not specified.

If you want to fill in the existing bitfields in a block of the next block, you can do so with a zero bit field of length as specified in the standard (6.7.2.1 # 11):

As a special case, a 0-width bit-field structure element indicates that no additional bit-field shall be packed into a block containing the previous bit-field, if any.

He goes on to say something about the end in C99 (6.7.2.1 # 15):



There may be an unnamed padding at the end of a structure or union.


What does this mean for your structure:

You var1

and var2

will be saved together in 4 bytes (32 bits) of memory without any spaces. Since the bit fields can work at the byte level, your var3

, and var4

also can be saved together to represent one byte. But the order of their implementation is determined. If you put a zero-length bit field in between, it var4

will start at the next aligned block. The end of your structure can be padded to 32 bits or 64 bits.


An example of real code with your structure:

Since you cannot accept bit field addresses, it is not easy to parse the bit field bahaviour, here is a small snippet of code I wrote to parse it with a little workaround. [/ p>

I am setting values ​​inside a structure with a bitmap that is easy to recognize and print out every bit of the whole structure (total size with sizeof()

). You can see the result at ideone or below. Note that the system being used uses little-endian format for each structured variable, so the bytes are swapped as opposed to human readable form (big-endian format). In addition, var3

and var4

are in a different order, since the standard states that this implementation is defined.

Output:

sizeof(my_struct)     = 8
sizeof(my_struct_var) = 8
Byte 0:  1 0 0 0 0 0 0 1 
Byte 1:  0 0 0 0 0 0 0 1 
Byte 2:  0 0 0 0 0 0 0 0 
Byte 3:  1 0 0 0 0 0 0 0 
Byte 4:  0 0 0 0 1 1 1 0 
Byte 5:  0 0 0 0 0 0 0 0 
Byte 6:  0 0 0 0 0 0 0 0 
Byte 7:  0 0 0 0 0 0 0 0 

      

Your structure effectively uses bytes 0 to 3 and a half bytes 4. Since I am compiled on a 64-bit machine and ideon, nibble 4 is padded with byte 7. I also recommend reading this guide on structure filling and bitfields .

Code:

#include <stdio.h>
#include <limits.h>

#if CHAR_BIT != 8
#error "unsupported char size"
#endif

typedef enum { ONE, TWO, THREE } my_enum;

typedef struct
{
   unsigned long var1 : 8;
   unsigned long var2 : 24;
   my_enum       var3 : 2;
   my_enum       var4 : 2;
} my_struct;

int main(void)
{
   int idx;
   int bitIdx;
   my_struct my_struct_var;

   memset (&my_struct_var,
           0,
           sizeof(my_struct_var));

   printf("sizeof(my_struct)     = %lu\n", sizeof(my_struct));
   printf("sizeof(my_struct_var) = %lu\n", sizeof(my_struct_var));

   my_struct_var.var1 = 0x81;     /* 1000 0001                     */
   my_struct_var.var2 = 0x800001; /* 1000 0000 0000 0000 0000 0001 */
   my_struct_var.var3 = 0b10;     /* 10                            */
   my_struct_var.var4 = 0b11;     /* 11                            */

   for (idx = 0; idx < sizeof(my_struct_var); ++idx)
   {
      char * curByte = &my_struct_var;
      curByte += idx;
      printf("\nByte %d:  ", idx);
      for (bitIdx = 0; bitIdx < CHAR_BIT; ++bitIdx)
      {
         printf("%c ", ((*curByte & (1 << ((CHAR_BIT - 1) - bitIdx))) >> ((CHAR_BIT - 1) - bitIdx)) + '0');
      }
   }

   return 0;
}

      

+1


source







All Articles