ProgrammationDéveloppeur C embarqué/bas niveau

Expliquez comment fonctionnent les unions dans le langage C. Quels problèmes résolvent-elles, comment les utiliser correctement et quels pièges typiques rencontrons-nous lors de leur utilisation ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse

Union (union) — c'est un type de données spécial qui stocke différentes valeurs dans la même zone de mémoire. Dans une union, tous les membres se trouvent à la même adresse en mémoire et la taille de la mémoire est égale à la taille du plus grand membre.

Utilisation :

  • pratique pour économiser de la mémoire si une variable prend un des plusieurs types de valeurs à un moment donné ;
  • permet d'interpréter les mêmes bits de différentes manières (par exemple, pour un accès bas niveau ou des protocoles).

Exemple :

union Data { int i; float f; char s[4]; }; union Data d; d.i = 0x41424344; // en mémoire, il y a maintenant 4 octets qui peuvent être lus comme int, float, chaîne printf("%c%c%c ", d.s[0], d.s[1], d.s[2]); // sortie spécifique au fournisseur

Pièges et règles d'utilisation :

  • Gardez dans l'union à tout moment un seul champ "significatif".
  • Il n'y a pas de suivi automatique du dernier champ "actif".
  • La lecture d'un champ inactif — comportement indéfini.
  • L'ordre des octets sur la plateforme est très important (endianness !)

Question piégeuse

Question : Quel est le sens de l'utilisation d'une union, lorsque l'on peut simplement utiliser une structure avec plusieurs champs ?

Réponse : L'utilisation d'une union économise de la mémoire, car à tout moment, une seule valeur est stockée, et non toutes en même temps. Dans une structure, chaque champ occupe de la mémoire, alors que dans une union, seule la mémoire nécessaire au maximum des champs est allouée, les autres "partagent" cette mémoire. De plus, l'union permet d'effectuer une conversion sécurisée ou intentionnelle entre différentes représentations de données dans un même fragment de mémoire.

Exemple :

struct S { int i; float f; } s; // sizeof = sizeof(int) + sizeof(float) union U { int i; float f; } u; // sizeof = max(sizeof(int),sizeof(float))

Exemples d'erreurs réelles


Histoire

Dans un projet de pilote de périphérique, la communication avec le "matériel" se faisait via une union avec accès bit à bit aux données. Après une petite refactorisation, le développeur a commencé à écrire dans le mauvais champ de l'union, ce qui a conduit à la lecture de données obsolètes et à des pannes fatales du système, car dans l'union, un seul champ est "réel" à chaque instant.


Histoire

Lors de l'échange de paquets réseau via une union pour gérer la mémoire, le développeur a oublié de prendre en compte l'alignement des structures. En conséquence, un décalage d'un octet s'est produit, et la structure a été analysée avec des décalages incorrects, rendant le protocole incompatible avec l'original.


Histoire

Dans le travail sur une bibliothèque de sérialisation, le programmeur a passé une union par valeur à une fonction, où le champ requis n'a pas été initialisé avant la lecture. Cela a entraîné une sérialisation incorrecte, des données indésirables dans le flux de sortie, et il était impossible de récupérer l'information d'origine.