Data Alignment, Data Structure Padding and C

Asked

Viewed 344 times

6

Can anyone explain to me how processing/compiling does padding? I don’t understand why the structure structc_t has a size of 24, shouldn’t it be 16 equal to structd_t? Note: Data on 64-bit Intel processor, 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));
}

1 answer

5

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

In the case of structc_t, the padding is added between the members c and d to ensure that the member of the type double is stored in a multiple memory position of 8. In the structd_t like the 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

Similarly, if you had reversed the order of the members of the type int and char of the second structure, 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 of 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 (whole field size), and in the case of structc_t would be more 4 bytes to be 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.

That one document (English) has a good description of C padding overall.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.