Data Alignment, Data Structure Padding and C

6

Can anyone explain how the render / compile does the padding? I do not understand why the structc_t structure has a size of 24, should not it be equal to the structd_t structure? Note: Data on Intel 64-bit, 64-bit Windows

#include <stdio.h>
// Dados em processador Intel 64 bits, Windows de 64 bits
typedef struct structa_tag{
   char        c; // size 1
   short int   s; // size 2
} structa_t; // size 3 + 1 Padding = 4 bytes
typedef struct structb_tag{
   short int   s; // size 2
   char        c; // size 1
   int         i; // size 4
} structb_t; // size 7 + 1 Padding = 8 bytes
typedef struct structc_tag{
   char        c; // size 1
   double      d; // size 8
   int         s; // size 4
} structc_t; // size 13 + 11 Padding = 24 bytes
typedef struct structd_tag{
   double      d; // size 8
   int         s; // size 4
   char        c; // size 1
} structd_t; // size 13 + 3 Padding = 16 bytes
void main(){
   structa_t A; structb_t B; structc_t C; structd_t D;
   printf("sizeof(structa_t) = %d\n", sizeof(A));
   printf("sizeof(structb_t) = %d\n", sizeof(B));
   printf("sizeof(structc_t) = %d\n", sizeof(C));
   printf("sizeof(structd_t) = %d\n", sizeof(D));
}
    
asked by anonymous 20.08.2014 / 04:12

1 answer

5

C variables are not placed in an arbitrary memory address. Each primitive type (with the exception of char , which occupies 1 byte) has an alignment requirement, which is the address type (in byte) where it can be located. char s can be located in any address, short (2 bytes) must be in addresses divisible by 2; int (and float ) in addresses divisible by 4, and double (and long long ) addresses divisible by 8. These alignment rules make access to variables more efficient since this "natural alignment" simple assembly instructions can access the data.

For structc_t , padding is added between the c and d members to ensure that the double member is stored in a multiple-memory location of 8. In structd_t as double is the first element, this 7-byte padding is not required.

typedef struct structc_tag{
   char        c; // size 1
   char        pad0[7];
   double      d; // size 8
   int         s; // size 4
   char        pad1[4];
} structc_t;

typedef struct structd_tag{
   double      d; // size 8
   int         s; // size 4
   char        c; // size 1
   char        pad0[3];
} structd_t; // size 13 + 3 Padding = 16 bytes

Likewise, if you had inverted the order of members of type int and char of the second structure, you would see that its size would also be different:

typedef struct structb2_tag {
   short int   s; // size 2
   int         i; // size 4
   char        c; // size 1
} structb2_t; // size 7 + 5 Padding = 12 bytes

is equivalent to

typedef struct structb2_tag {
   short int   s; // size 2
   char        pad0[2];
   int         i; // size 4
   char        c; // size 1
   char        pad1[3];
} structb2_t; // size 7 + 5 Padding = 12 bytes

To complete, the padding at the end of the structure is added to ensure that its size is multiple of the largest of its members. In the case of structb2_t above, it needs 3 more bytes to be a multiple of 4 (integer field size), and in the case of structc_t it would be 4 more bytes to be a multiple of 8 (field size double ). This is necessary in case the structure is used in an array, for example, where the elements are stored contiguously in memory, and the alignment rules are preserved.

This document (English) has a good description of padding in C in general.

    
20.08.2014 / 04:57