[C] Structure padding

Published 12-03-2018

Nous allons voir dans cet article que la taille d’une structure est peux être plus grande que ce que vous pensez et comment optimiser l’espace en RAM.

Un ordinateur lie et écrit en mémoire à une adresse divisible par 4 (x86) ou divisible par 8 (x86_64).

Quelle est la taille de cette structure ?

typedef struct structure
{
	char a;
	int b;
	char c;
	char *d;
	short e;
} structure;

Rapelle :

Sur un system 64 bits :

  • char : 1 octet
  • short : 2 octets
  • int : 4 octets
  • pointeur : 8 octets
~/Documents/blog(master*) » clang main.c
~/Documents/blog(master*) » ./a.out
sizeof struct : 32

Lorsque vous allez compiler le code du dessus, votre compilateur va ajouter des octets de padding à votre structure

~/Documents/blog(master*) » clang -Wpadded main.c
main.c:6:7: warning: padding struct 'struct pad' with 3 bytes to align 'b'
[-Wpadded]
int b;
^
main.c:8:8: warning: padding struct 'struct pad' with 7 bytes to align 'd'
[-Wpadded]
char *d;
^
main.c:3:16: warning: padding size of 'struct pad' with 6 bytes to alignment
boundary [-Wpadded]
typedef struct pad
^
3 warnings generated.

Structure aligne par le compilateur:
------------------------------------
|X...|XXXX|X.......|XXXXXXXX|XX......|
------------------------------------

Avec le flag -Wpadded, on voit que clang ajoute les octets de padding au bon endroit.

Pourquoi aligner une structure alors que le compilateur le fait ?

Le compilateur ne fait qu’ajouter des octets de padding et ne modifie pas l’ordre des variables dans la structure.

La même structure qu’au dessus aligner manuellement.

typedef struct structure
{
	char *d;
	int b;
	short e;
	char a;
	char c;
} structure;

Stucture manuellement aligner :
--------------------
|XXXXXXXX|XXXX|XX|X|X|
--------------------
~/Documents/blog(master*) » clang -Wpadded main.c
~/Documents/blog(master*) » ./a.out
sizeof struct : 16

Sur cet exemple, on gagne 16 octets. On a divisé par deux la taille de notre structure ce qui n’est pas négligeable.

Sur un code simple comme celui la, ce n’est pas très important, mais imaginez sur un code comme celui du kernel linux.

Ou meme sur des périphériques embarque comme un arduino, teensy, micro controlleur etc …

Quand on cree une structure, une bonne pratique est de déclarer les variables de la plus grande a la plus petite.

On peut aussi ajouter l’attribut packed pour que le compilateur pad la structure en question.

typedef struct structure
{
	char a;
	int b;
	char c;
	char *d;
	short e;
} __attribute__((packed)) structure;

Ou sinon pour padder toutes les structures on peut ajouter au début du code :

#pragma pack(1)