289 votes

Le but des Syndicats en C et C++

J'ai utilisé les syndicats plus tôt confortablement; aujourd'hui, j'ai été effrayé quand j'ai lu ce post et est venu de savoir que ce code

union ARGB
{
    uint32_t colour;

    struct componentsTag
    {
        uint8_t b;
        uint8_t g;
        uint8_t r;
        uint8_t a;
    } components;

} pixel;

pixel.colour = 0xff040201;  // ARGB::colour is the active member from now on

// somewhere down the line, without any edit to pixel

if(pixel.components.a)      // accessing the non-active member ARGB::components

est en fait un comportement indéterminé I. e. lecture à partir d'un membre de l'union autres que celle qui s'est récemment écrit à conduit à un comportement indéterminé. Si ce n'est pas le but de l'utilisation des syndicats, c'est quoi? Certains ont-ils un s'il vous plaît expliquer minutieusement?

Mise à jour:

Je tenais à préciser un peu les choses avec du recul.

  • La réponse à la question n'est pas la même pour le C et le C++; mon ignorance jeune marqués à la fois comme le C et le C++.
  • Après avoir écumé par le biais de C++11 est la norme, je ne pouvais pas dire avec certitude qu'il appelle d'accéder à l'inspection d'un non-actif membre de l'union n'est pas défini/non/de mise en œuvre définies. Tout ce que je pouvais trouver §9.5/1:

    Si un modèle de mise en page de l'union contient plusieurs normes-mise en page des structures qui partagent une même séquence initiale, et si un objet de la présente norme-mise en page type d'union contient l'un des standard-layout structures, il est autorisé à inspecter la commune de séquence initiaux de l'un de standard-layout les membres de la structure. §9.2/19: standard-layout structures partagent une séquence initiale si les membres correspondants ont mise en page des types compatibles et soit ni membre est un peu de champ, ou les deux, sont peu-champs, avec la même largeur pour une séquence d'un ou de plusieurs membres initiaux.

  • Alors que dans C (C99 TC3 - DR 283 et suivantes), il est légal de le faire (merci à Pascal Cuoq pour s'élever). Cependant, tenter de le faire , elle peut encore conduire à un comportement indéfini, si la valeur lue se passe invalide ("piège de la représentation") pour le type c'est de lire à travers. Sinon, la valeur lue est définie par l'implémentation.
  • C89/90 appelé ce en vertu de comportement non spécifié (Annexe J) et K&R du livre dit qu'elle est définie par l'implémentation. Citation de K&R:

    C'est le but d'une union - une seule variable qui peut légitimement tenir l'un d'un de plusieurs types. [...] tant que l'utilisation est conforme: le type (extrait doit être le type le plus récemment enregistrés. C'est le programmeur a la responsabilité de garder une trace de quel type est actuellement stockées dans une union; les résultats sont dépendant de l'implémentation si quelque chose est stocké comme un type et extrait comme de l'autre.

  • Extrait de Stroustrup TC++PL (l'emphase est mienne)

    L'utilisation de syndicats peut être essentiel pour compatness de données [...] parfois utilisé pour le "type de conversion".

Par-dessus tout, cette question (dont le titre reste inchangé depuis mon ask) a été posée avec l'intention de comprendre le but des syndicats ET non pas sur ce qu'est la norme permet à E. g. L'utilisation de l'héritage pour la réutilisation de code est, bien sûr, autorisée par la norme C++, mais ce n'était pas le but ou l'intention d'origine de l'introduction de l'héritage en C++ le langage. C'est la raison pour Andrey réponse continue à rester comme acceptée.

469voto

AndreyT Points 139512

L'objectif des syndicats est assez évident, mais pour une raison quelconque les gens manquent assez souvent.

Le but de l'union est d'économiser de la mémoire en utilisant la même zone de mémoire pour le stockage des objets différents à des moments différents. C'est tout.

C'est comme une chambre dans un hôtel. Différentes personnes de l'utiliser pour le non-chevauchement des périodes de temps. Ces gens ne se rencontrent jamais, et n'ont généralement pas besoin de savoir quelque chose au sujet de chaque d'autres.

C'est exactement ce que l'union de fait. Si vous savez que plusieurs objets dans votre programme de détenir des valeurs de non-cumul de la valeur-la durée de vie, alors vous pouvez "fusionner" ces objets dans une union et, ainsi, économiser de la mémoire. Tout comme une chambre d'hôtel a au plus un "actif" locataire à chaque moment du temps, un syndicat a au plus un "actif" membre de, à chaque moment de temps du programme. Seuls les "actifs" d'un membre peut être lu. Par écrit dans autre membre vous changez le statut "actif" pour que les autres membres.

Pour quelque raison, cette origine, l'objectif de l'union est "remplacé" par quelque chose de complètement différent: l'écriture d'un membre d'un syndicat, et ensuite d'inspecter par un autre membre. Ce type de mémoire réinterprétation n'est pas une utilisation valide de syndicats. Il conduit généralement à un comportement indéfini.

40voto

ammoQ Points 17866

Vous pouvez utiliser des syndicats pour créer des structures comme le suivant, qui contient un champ qui nous dit quel composant de l'union est actuellement utilisées:

struct VAROBJECT
{
    enum o_t { Int, Double, String } objectType;

    union
    {
        int intValue;
        double dblValue;
        char *strValue;
    } value;
} object;

34voto

Le comportement est indéfini de la langue du point de vue. Considérer que les différentes plates-formes peuvent avoir différentes contraintes dans l'alignement de la mémoire et de stockage. Le code dans un big endian par rapport à un petit-boutiste de la machine sera mise à jour les valeurs dans la structure différemment. La fixation du comportement dans la langue exigerait que toutes les implémentations à l'utilisation de la même endianness (et de mémoire de l'alignement des contraintes...) limitation de l'utilisation.

Si vous êtes à l'aide de C++ (vous êtes à l'aide de deux balises) et vous vous souciez vraiment de la portabilité, vous pouvez simplement utiliser la structure et de fournir un setter qui prend l' uint32_t et définit les champs de manière appropriée par le biais de masque de bits des opérations. La même chose peut être fait en C avec une fonction.

Edit: je m'attendais à AProgrammer à écrire une réponse à voter et fermer celui-ci. Comme certains commentaires l'ont souligné, endianness est traitée dans d'autres parties de la norme en permettant à chaque mise à décider quoi faire, et l'alignement et le rembourrage peut également être traitées différemment. Maintenant, la stricte aliasing règles qui AProgrammer implicitement fait référence à sont un point important ici. Le compilateur est autorisé à faire des hypothèses sur la modification (ou l'absence de modification) des variables. Dans le cas de l'union, le compilateur pourrait réorganiser les instructions et déplacer la lecture de chaque composant de la couleur sur l'écriture de la couleur variable.

8voto

Totonga Points 2162

En C c'était une belle façon de mettre en œuvre quelque chose comme une variante.

enum possibleTypes{
  eInt,
  eDouble,
  eChar
}


struct Value{

    union Value {
      int iVal_;
      double dval;
      char cVal;
    } value_;
    possibleTypes discriminator_;
} 

switch(val.discriminator_)
{
  case eInt: val.value_.iVal_; break;

En temps de litlle la mémoire de cette structure est d'utiliser moins de mémoire qu'une structure qui dispose de tous les membres.

Par la voie C

    typedef struct {
      unsigned int mantissa_low:32;      //mantissa
      unsigned int mantissa_high:20;
      unsigned int exponent:11;         //exponent
      unsigned int sign:1;
    } realVal;

pour accéder aux valeurs des bits.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X