Quels sont les avantages des structures / unions non nommées en C?

J’ai trouvé un code implémenté sous la forme d’une démo similaire ci-dessous.

struct st { int a; struct { int b; }; }; 

6.58 Champs de structs/unions dans les structs/unions

Comme autorisé par ISO C11 .

Mais quels en sont les avantages?

Parce que de toute façon je peux accéder aux données membres de la même manière, comme

 int main() { struct st s; sa=11; sb=22; return 0; } 

compilé sur gcc 4.5.2 avec,

 gcc -Wall demo.c -o demo 

et pas d’erreurs,

Cela ne doit pas forcément être une structure anonyme dans une structure, ce que je ne trouve pas très utile: cela ne modifiera que légèrement la mise en page en introduisant plus de padding, sans autre effet visible (par rapport à l’inclusion des membres de la structure enfant dans la structure parente).

Je pense que l’avantage des structures / unions anonymes est ailleurs: elles peuvent être utilisées pour placer une structure anonyme dans une union ou une union anonyme dans une structure.

Exemple:

 union u { int i; struct { char b1; char b2; char b3; char b4; }; }; 

L’avantage est assez évident, n’est-ce pas? Cela évite au programmeur d’avoir un nom! Comme il est difficile de nommer les choses , il est bien qu’il soit possible d’éviter de le faire s’il n’est pas vraiment nécessaire.

C’est aussi un signe assez clair que cette struct est locale et n’a jamais été utilisée ailleurs que dans le contexte d’être un champ dans la structure parente, ce qui est vraiment une très bonne information car elle réduit les possibilités de couplage inutile.

Pensez-y comme static ; il limite la visibilité de la struct interne à la struct externe, de manière similaire (mais pas identique, bien entendu) à la manière dont static limite la visibilité des symboles globaux à l’unité de compilation dans laquelle ils apparaissent.

Je viens de rencontrer un énorme avantage de l’ union anonyme. Cependant, soyez averti que ceci n’est pas une histoire pour les âmes sensibles ni une pratique recommandée.

Dans un programme C plus ancien comprenant des centaines de fichiers de code source, il existe une variable globale, une struct , qui contenait une struct tant que membre. Ainsi, la définition du type de la variable globale ressemblait à quelque chose comme:

 typedef struct { LONG lAmount; STRUCTONE largeStruct; // memory area actually used for several different struct objects ULONG ulFlags; } STRUCTCOMMON; 

La struct , STRUCTONE, était l’une de plusieurs grandes structures, mais toutes les autres étaient plus petites que STRUCTONE au moment de la rédaction de ce code. Donc, cette zone de mémoire, largeStruct était utilisée comme une union mais sans les déclarations source appropriées l’indiquant. À la place, diverses variables de struct ont été copiées dans cette zone à l’aide de memcpy() . Pour aggraver les choses, cela se faisait parfois par le nom même de la variable globale et parfois par un pointeur sur la variable globale.

Comme cela se produit généralement à mesure que le temps avance, les modifications récentes ont eu pour résultat que l’une des autres structures est devenue la plus importante. Et j’étais confronté à une centaine de fichiers à rechercher pour savoir où cela était utilisé ainsi que tous les divers pseudonymes et tout le rest.

Et puis je me suis souvenu des syndicats anonymes. J’ai donc modifié le typedef comme suit:

 typedef struct { LONG lAmount; union { // anonymous union to allow for allocation of largest space needed STRUCTONE largeStruct; // memory area actually used for several different struct objects STRUCTTHREE largerStruct; // memory area for even larger struct }; ULONG ulFlags; } STRUCTCOMMON; 

Et puis tout recompilé.

Alors maintenant, tous ces jours d’examen du code source et de tests de régression que j’espérais malheureusement ne sont plus nécessaires.

Et je peux maintenant commencer le processus de modification lente de la source en utilisant cette clé globale pour amener cette source à des normes plus modernes que mon propre calendrier.