Bitfield alignment (gcc) in structure

Question:

I read the article and decided to apply the packaging, but it turned out to be not as simple as described.

There is such a structure

struct info {
  VipsImage  *in, *out;
  unsigned    buff_len:24;
  unsigned    name_len:8;
  unsigned    height:10;
  unsigned    w:10;        
  unsigned    h:10;  
  unsigned    isWebp:1;    
  unsigned    isBig:1;
};

It weighs 24 bytes on a 64-bit architecture. It is worth rearranging the name_len member below for ten-bit members, as the structure begins to weigh already 32 bytes (it’s just mystical how much garbage the compiler adds with the same values ​​​​in bit fields, but not correctly placed in the structure) I found the first indent, but the second is not yet there, it looks the whole thing is like this (rearranged name_len and added 30 bits of padding_1 in order to try to understand exactly how the compiler aligns in this case, as a result, the structure remained to weigh 32 bytes and, as I understand it, this is not all rubbish …) :

struct info {
  VipsImage  *in, *out;
  unsigned    buff_len:24;
  unsigned    height:10;
  unsigned    padding_1:30; 
  unsigned    w:10;        
  unsigned    h:10;
  unsigned    name_len:8;
  unsigned    isWebp:1;    
  unsigned    isBig:1;
};

I tried to place it as described in the article according to the principle (arrange the elements of the structure by decreasing size), but it turned out that this does not work with bit fields. How exactly occurs in this case alignment of bit fields? and why does the compiler so strangely align bit fields according to the size of the pointer in the structure?

PS Compiler version gcc version 6.3.0 20170516 (Debian 6.3.0-18+deb9u1)

Answer:

The article at your link describes how bit fields are aligned – according to the machine word (32-bit) declared by you as unsigned.

struct info {
    VipsImage  *in, *out; // 4 слова (64 + 64)
    
    unsigned    buff_len:24;
    unsigned    name_len:8; //эти два поля влезают в 32 бита - 1 слово
    
    unsigned    height:10;
    unsigned    w:10;        
    unsigned    h:10;  
    unsigned    isWebp:1;    
    unsigned    isBig:1; // эти поля влезают в еще одно слово (32-бита)
};
// итого 64 + 64 + 32 + 32 = 192 (24 байта)

struct info {
    VipsImage  *in, *out; // 4 слова (64 + 64)
    
    unsigned    buff_len:24;    // под это поле зарезервируется слово (32-бита) потому что следующее поле не влезает в слово
    unsigned    height:10;      // под это поле зарезервируется слово (32-бита) потому что следующее поле не влезает в слово
    unsigned    padding_1:30;   // под это поле зарезервируется слово (32-бита) потому что следующее поле не влезает в слово
    
    unsigned    w:10;        
    unsigned    h:10;
    unsigned    name_len:8;
    unsigned    isWebp:1;    
    unsigned    isBig:1;        // под эти поля зарезервируется слово (32-бита), но использоваться будут только 30-бит
};
// итого 64 + 64 + 32 + 32 + 32 + 32 = 256 (32 байта)
Scroll to Top