Utilisez struct Alignment and Padding en C

Jinku Hu 12 octobre 2023
  1. Comprendre les bases de l’alignement et du remplissage en C
  2. Utiliser la technique de réorganisation des membres pour économiser de l’espace dans les objets en C
Utilisez struct Alignment and Padding en C

Cet article explique plusieurs méthodes d’utilisation de l’alignement et du remplissage de struct en C.

Comprendre les bases de l’alignement et du remplissage en C

Tous les objets en mémoire sont représentés comme les types de données primaires comme: char, short, int, long, pointer etc. Ces types de données ont leur taille correspondante en mémoire. Sur la plupart des processeurs de bureau 64 bits contemporains, les tailles sont de 1 octet pour un char, 2 octets pour un court, 4 octets pour un int, 8 octets pour un pointeur, etc. Notez que ce ne sont pas des tailles garanties (sauf pour char), mais on peut récupérer la taille de l’objet en utilisant l’opérateur sizeof. Désormais, l’alignement est la méthode employée par les compilateurs pour placer des variables dans la mémoire, ce qui implique que chaque type de données de base est stocké à l’adresse divisible par la taille correspondante.

Habituellement, l’alignement est utilisé pour accéder aux objets de données plus rapidement et plus efficacement. L’alignement force les différents types de données déclarés en permanence à inclure un certain espacement entre leurs adresses. À savoir, si nous déclarons une structure st1 avec un pointeur et un char comme indiqué dans l’exemple suivant, cela prendra 16 octets au total. Attention cependant, un seul pointeur prend 8 octets et un char prend un octet, donc on pourrait penser que la structure st1 doit occuper 9 octets. Mais il se comporte comme si tous les membres étaient alignés sur la plus grande taille du membre (c’est-à-dire 8 octets). La structure st2 démontre une structure similaire qui occupe la même quantité de mémoire, sauf qu’elle a un tableau de 7 membres char.

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char const *argv[]) {
  typedef struct {
    char *p;
    char c2;
  } st1;

  typedef struct {
    char *p;
    char c2;
    char padding[7];
  } st2;

  printf("sizeof st1 = %zu\n", sizeof(st1));
  printf("sizeof st2 = %zu\n", sizeof(st2));

  exit(EXIT_SUCCESS);
}

Production:

sizeof st1 = 16
sizeof st2 = 16

Utiliser la technique de réorganisation des membres pour économiser de l’espace dans les objets en C

L’exemple précédent montre qu’il y a un gaspillage de mémoire lorsque les structures incluent différents types et ne remplissent pas les limites d’alignement. Cependant, dans certains cas, il peut être possible de réorganiser les membres de la structure et d’économiser de l’espace supplémentaire.

L’exemple de code suivant définit la structure foo1 qui a le plus grand membre (char *) au milieu et foo2 avec le même membre que le premier. Les tailles de ces deux objets sont différentes - 24 octets et 16 octets. Cela a à voir avec l’ordre des membres de données. Dans la structure foo1, p doit être aligné à l’adresse qui est divisible par 8, donc les int et short avant d’occuper 8 octets au total et deux char * après qu’il occupera les 8 octets également. Bien que, si nous déplaçons p à la première place, les membres suivants se faufileront dans les 8 octets et la règle d’alignement sera également satisfaite. Ainsi, la taille de foo2 totalise 16 octets et elle est appelée pour être compressée struct. Notez que le compilateur gcc a le spécificateur spécial __attribute__ ((packed)) qui peut forcer même les membres struct non ordonnés à être compressés.

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char const *argv[]) {
  typedef struct {
    int n1;
    short s1;
    char *p;
    char c1;
    char c2;
  } foo1;

  typedef struct {
    char *p;
    int n1;
    short s1;
    char c1;
    char c2;
  } foo2;

  typedef struct {
    int n1;
    short s1;
    char *p;
    char c1;
    char c2;
  } __attribute__((packed)) foo3;

  printf("sizeof foo1 = %zu\n", sizeof(foo1));
  printf("sizeof foo2 = %zu\n", sizeof(foo2));
  printf("sizeof foo3 = %zu\n", sizeof(foo3));

  exit(EXIT_SUCCESS);
}

Production:

sizeof foo1 = 24
sizeof foo2 = 16
sizeof foo3 = 16
Auteur: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.

LinkedIn Facebook

Article connexe - C Struct