2010-07-31 5 views
3

Tous,Structures et Unions en C, détermination de la taille et accès aux membres

Voici un exemple sur les unions que je trouve confus.

struct s1 
{ 
    int a; 
    char b; 
    union 
    { 
     struct 
     { 
      char *c; 
      long d; 
     } 
     long e; 
    }var; 
}; 

Considérant que char est égal à 1 octet, int est de 2 octets et long est de 4 octets. Quelle serait la taille de la structure entière ici? La taille de l'union sera-t-elle {taille de char *} + {taille du double}? Je suis confus à cause de la structure enveloppée dans le syndicat.

En outre, comment puis-je accéder à la variable d dans la structure. var.d?

+2

Vous ne pouvez pas en être certain, car le compilateur peut gérer ces constructions pour un meilleur alignement des données. – Joe

+0

Mais le rembourrage est une option que le programmeur doit mentionner à droite? Quelle serait la disposition de la mémoire si le code est compilé comme il est ci-dessus –

+0

Non, le compilateur peut (et souvent va) insérer padding par défaut. –

Répondre

1

Sans rembourrage, et en supposant sizeof (int) == sizeof (char *) == sizeof (long) == 4, la taille de la structure extérieure sera 13.

Décomposant, la union var chevauche une structure anonyme avec un seul long. Cette structure interne est plus grande (un pointeur et un long) de sorte que sa taille contrôle la taille de l'union, ce qui fait que l'union consomme 8 octets. Les autres membres sont 4 octets et 1 octet, donc le total est 13.

Dans toute implémentation sensible avec les hypothèses de taille que j'ai faites ci-dessus, cette structure sera complétée à 2 octets ou 4 octets, en ajoutant au moins 1 ou 3 octets supplémentaires à la taille. En général, comme les tailles de tous les types de membres sont elles-mêmes définies par l'implémentation et que le remplissage est défini par l'implémentation, vous devez vous référer à la documentation pour votre implémentation et à la plate-forme pour être sûr.

L'implémentation est autorisée à insérer un remplissage après essentiellement tout élément d'une structure. Les mises en œuvre judicieuses utilisent un minimum de rembourrage pour répondre aux exigences de la plate-forme (par exemple, les processeurs RISC exigent souvent qu'une valeur soit alignée sur la taille de cette valeur) ou pour des performances. Si vous utilisez une structure pour mapper des champs à la disposition des valeurs assumées par spécification de format de fichier, un coprocesseur dans la mémoire partagée, un périphérique matériel ou tout autre cas où l'empaquetage et la disposition importent réellement, alors vous pourriez vouloir vous êtes préoccupé par le fait que vous testez au moment de la compilation ou de l'exécution que vos suppositions de la disposition des membres sont vraies. Cela peut être fait en vérifiant la taille de la structure entière, ainsi que les décalages de ses membres. Entre

Voir this question entre autres pour une discussion des astuces d'assertion à la compilation.

5

Les tailles sont définies par l'implémentation, en raison du remplissage. Une union aura au moins la taille du plus grand membre, tandis qu'une structure sera au moins la somme des tailles des membres. La structure interne sera à moinssizeof(char *) to sizeof(long), donc l'union sera au moins aussi grande. La structure externe sera au moins sizeof(int) + 1 + sizeof(char *) + sizeof(long). Toutes les structures et unions peuvent avoir un remplissage. Vous utilisez une extension à la norme, unnamed fields. En ISO C, il n'y aurait aucun moyen d'accéder à la structure interne. Mais dans GCC (et je crois que MSVC), vous pouvez faire var.d.

De plus, il vous manque le point-virgule après la structure interne.

-3

Les syndicats sont dangereux et dangereux à utiliser sans discipline stricte. Et le fait que vous le mettiez dans une structure est vraiment dangereux car par défaut tous les membres de la structure sont publics: cela expose la possibilité que le code client apporte des modifications à votre union, sans informer votre programme du type de données qu'il contient. Si vous utilisez une union, vous devriez la mettre dans une classe où au moins vous pouvez la cacher en la rendant privée.

Nous avions un an auparavant qui buvait le koolaid des unions, et le mettait dans toutes ses structures de données. En conséquence, les caractéristiques qu'il a écrites avec lui, sont maintenant l'une des parties les plus méprisées de notre application entière, car ils sont non modifiables, unfixable et incompréhensible.

De plus, les Unions rejettent toute la sécurité que les compilateurs c/C++ modernes vous offrent. Sûrement si vous mentez au compilateur il vous reviendra un jour. Eh bien en fait, il reviendra à votre client lorsque votre application se bloque.

+1

Vous pouvez remarquer que cette question est marquée C, mais pas * C++. Oui, c'est un cas rare où l'OP a correctement identifié le langage plutôt que de parler d'un hybride C/C++ mythique. En tout cas, il pose des questions sur C et les classes et la protection ne sont pas des caractéristiques du langage C. – RBerteig

Questions connexes