Qu'est-ce que struct (structure C) ?

Mécanisme du C qui regroupe plusieurs valeurs (membres), éventuellement de types différents, en un seul type. On la définit par exemple avec struct sensor { int id; float value; }; on utilise alors les membres d'une variable s sous la forme s.id, et à travers un pointeur p sur une struct sous la forme p->id. Les membres sont rangés en mémoire dans l'ordre de déclaration, mais du remplissage (padding) peut être inséré entre eux pour l'alignement, si bien que la taille totale peut dépasser la somme des tailles des membres.

Nom japonais: 構造体

« struct (structure C) » apparaît dans 11 questions d'entraînement réparties sur 7 thèmes, dont ISA et assembleur, Bases de la programmation en C, Systèmes embarqués et firmware.

Domaine: Bases de la programmation en C

Définition et utilisation

Avec la définition struct point { int x; int y; };, on crée une variable comme struct point p = {1, 2}; et on utilise chaque membre sous la forme p.x ou p.y. Donner un alias avec typedef, comme typedef struct { … } Point;, permet de déclarer Point p; sans écrire struct. Les structs peuvent être affectées d'un bloc avec =, passées en argument à des fonctions et servir de valeur de retour, mais on passe en général les grandes structs par pointeur.

Disposition en mémoire

Les membres sont placés dans l'ordre de déclaration, des adresses basses vers les adresses hautes. Du remplissage (padding) est inséré avant un type qui doit être aligné, comme un int de 4 octets sur une frontière de 4 octets, et la taille de la struct entière est arrondie à un multiple de son alignement le plus strict. Ainsi, une struct contenant char, int et char dans cet ordre occupe 12 octets dans un environnement courant où int fait 4 octets, et placer l'int en premier la réduit à 8 octets.

Pièges en embarqué et dans les communications

Représenter la disposition des registres d'un périphérique par une struct est courant, mais le padding et l'ordre des bits des champs de bits peuvent varier selon l'implémentation : les utiliser sans vérification peut décaler les adresses. Traiter des données de communication ou un format de fichier comme l'image mémoire brute d'une struct rompt la compatibilité avec d'autres environnements, à cause des différences de padding et d'endianness ; on assemble donc souvent les données octet par octet.

S'entraîner : questions sur struct (structure C)

Lorsqu'on représente les registres d'un périphérique par une structure C à champs de bits, à quoi faut-il prendre garde ?

  1. ALes champs de bits rendent toujours le programme deux fois plus rapide
  2. BL'ordre des bits notamment peut varier selon le compilateur, si bien qu'un autre compilateur peut manipuler des bits différents de ceux prévus
  3. CLes champs de bits ne peuvent pas représenter de valeurs de plus de 8 bits
Afficher la réponse et l'explication

Réponse : B. L'ordre des bits notamment peut varier selon le compilateur, si bien qu'un autre compilateur peut manipuler des bits différents de ceux prévus

Les champs de bits rendent le code lisible, mais la norme C laisse à l'implémentation l'ordre des bits dans la struct (du poids fort ou du poids faible), le traitement des champs chevauchant une frontière, la largeur des accès, etc. Un code correct avec un compilateur peut donc lire ou écrire des bits différents avec un autre compilateur ou un autre processeur. Les en-têtes fournis par les fabricants de microcontrôleurs sont le plus souvent écrits avec des masques et des décalages.

Questions fréquentes

Quelle différence y a-t-il entre une struct et un tableau ?

Un tableau aligne des éléments du même type, que l'on choisit par un indice. Une struct regroupe des membres de types éventuellement différents, que l'on choisit par leur nom. Les deux se combinent souvent, comme dans un tableau de structs ou une struct qui a un tableau comme membre.

Pourquoi faut-il vérifier la taille d'une struct avec sizeof ?

La quantité de padding entre les membres et après le dernier dépend de la taille des types et des règles d'alignement (l'ABI) : additionner les tailles des membres ne donne pas la bonne taille. Pour allouer une struct avec malloc ou l'écrire dans un fichier, on obtient sa taille réelle avec sizeof(struct nom).

« struct (structure C) » dans les explications

Questions mentionnant « struct (structure C) » (11)

  1. Lorsqu'on représente les registres d'un périphérique par une structure C à champs de bits, à quoi faut-il prendre garde ?
  2. Quel est le fonctionnement correct de l'instruction RISC-V « lw t0, 8(sp) » ?
  3. Dans la convention d'appel standard de RISC-V, lors de l'appel d'une fonction à 10 arguments entiers, où sont transmis les 9e et 10e arguments ?
  4. En RISC-V, si l'adresse d'une instruction lw lisant 4 octets n'est pas un multiple de 4 (non alignée), que peut-il se passer ?
  5. Quelle description de l'ABI (interface binaire d'application) est correcte ?
  6. Sous Linux, dans quel cas incrémente-t-on généralement le numéro de version du soname, comme le « .1 » de libfoo.so.1 ?
  7. Pourquoi le traitement ci-dessus, qui additionne uniquement les coordonnées x, devient-il généralement plus rapide une fois réécrit sous forme de structure de tableaux (chaque composante dans un tableau séparé) ?
  8. Un faux partage se produit dans un tableau de compteurs par thread déclaré « long cnt[8]; ». Quelle est la mesure la plus appropriée ?
  9. Pour traiter sur GPU des données de particules ayant des positions x, y et z, quelle disposition est avantageuse du point de vue de l'accès mémoire coalescé ?
  10. On considère un environnement courant où char fait 1 octet et int 4 octets, et où les int sont placés à des adresses multiples de 4. Quelle est la sortie obtenue en exécutant le code ci-dessus ?
  11. Le fichier d'en-tête sensor.h est écrit comme ci-dessus. Quel est le rôle des trois lignes #ifndef, #define et #endif ?

Termes associés

Tableau Variable Convention d'appel Argument Pointeur Alignement et remplissage (padding) SIMD Champ de bits (bit-field) Mode d'adressage Pile (stack)

Retour au glossaire