IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

union versus struct


Sujet :

C

  1. #1
    Expert confirmé
    Avatar de gerald3d
    Homme Profil pro
    Conducteur de train
    Inscrit en
    Février 2008
    Messages
    2 315
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Conducteur de train
    Secteur : Transports

    Informations forums :
    Inscription : Février 2008
    Messages : 2 315
    Billets dans le blog
    5
    Par défaut union versus struct
    Bonsoir tout le monde.

    Cela fait maintenant plusieurs années que j'écris des lignes de code en C sans jamais avoir utilisé union. Jusqu'à présent je n'en ressens aucun besoin et m'en suis passé sans problème .

    Cependant, puisque cette forme d'encapsulation de données existe, c'est qu'elle doit bien avoir un intérêt.

    Hormis le gain de mémoire utilisée*, quel peut être l'autre intérêt d'utiliser union à la place de struct ?






    * L'un(e) d'entre vous pourrait-il m'expliquer comment on peut économiser de la mémoire avec un union ? Je comprends bien le fait d'accéder à une donnée à la fois, mais toutes les données sont toutes en mémoire. À moins que ce soit sur ce point que je me fourvoie...

  2. #2
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 026
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 026
    Par défaut
    Une union n'a rien à voir avec un struct.

    Un struct permet de stocker plusieurs variables de types différents et a une taille égale à la somme de la taille des variables qu'elle contient.

    Une union permet de stocker une seule variable à la fois mais qui peut être de plusieurs type. La taille d'une union est donc la taille du type le plus gros qu'elle peut contenir.

    exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    typedef union
    {
         int x;
         float y;
    }MonUnion;
     
    MonUnion toto;
    La taille de l'union sera de sizeof(float).
    On pourra soit stocker un int, soit stocker un float mais pas les deux.

    A noter que si on stocke un int, rien n'empêche de faire : toto.y ce qui retournera un float.
    Le float, plus grand que l'int sera donc composé de l'int ainsi que quelques octets indéterminé.

    Inversement, on peut aussi stocker un float et faire toto.x ce qui retournera un int.
    L'int, plus petit que le float, sera composé de quelques octets du float mais pas tous.

  3. #3
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 485
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 485
    Par défaut
    Hello,

    — Sur le plan de la syntaxe, « union » s'utilise exactement comme « struct » ;
    — Sur le plan de la mémoire, les membres d'une union partagent tous le même emplacement mémoire. Par conséquent, quand tu écris dans un membre, tu écrases les autres, et la taille d'une union est celle du membre le plus grand.

    C'est utile quand tu ne sais pas à l'avance quel est le type du paramètre que tu vas recevoir… ou renvoyer ! Car une union est un type tout-à-fait légitime qui peut être appliqué à une fonction (comprendre par là : à ce qu'elle renvoie). Si tu écris :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    union {
    int i;       /* Entier */
    char * s;    /* Chaîne */
    double d;   /* Float */ }
    … et que tu as un moyen par ailleurs de savoir quel paramètre est valide à un moment donné, alors tu peux garder la sémantique et les contrôles à la compilation plutôt que référencer le paramètre avec un pointeur « void * » et laisser le compilateur travailler à l'aveugle.

  4. #4
    Expert confirmé
    Avatar de gerald3d
    Homme Profil pro
    Conducteur de train
    Inscrit en
    Février 2008
    Messages
    2 315
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Conducteur de train
    Secteur : Transports

    Informations forums :
    Inscription : Février 2008
    Messages : 2 315
    Billets dans le blog
    5
    Par défaut
    Intéressante ton explication.

    Pourrait-on rapprocher (de loin tout même le fonctionnement d'une union avec les template en C++ ?

    Par exemple une union :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    typedef union {
    char w;
    int x;
    float y;
    double z;
    } BaseType;
    Et ensuite l'utiliser sur une fonction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    BaseType addition (BaseType a, BaseType b);

  5. #5
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 485
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 485
    Par défaut
    Citation Envoyé par gerald3d Voir le message
    Pourrait-on rapprocher (de loin tout même le fonctionnement d'une union avec les template en C++ ?

    Par exemple une union :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    typedef union {
    char w;
    int x;
    float y;
    double z;
    } BaseType;
    De très loin, alors. « union » existe toujours en C++ et le code template est un concept très différent. Par contre, les unions (avec les structures, d'ailleurs) ont été largement utilisés pour implémenter les concept objets.

    La seule chose qu'il faut retenir est que dans le cas d'une structure, tes éléments sont disposés en mémoire comme suit :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    0  0           0           0                       1
    0  1           5           9                       7
    |  |           |           |                       |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |c | int x     | float y   | double z              |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

    … alors que dans le cas d'une union, tu obtiens ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    0                       0
    0                       8
    |                       |
    +--+--+--+--+--+--+--+--+
    |c |        |           |
    +--+        |           |
    | int x     |           |
    +--+--+--+--+           |
    | float y   |           |
    +--+--+--+--+           |
    | double z              |
    +--+--+--+--+--+--+--+--+

    … c'est-à-dire que tous les éléments sont confondus à la même position mémoire.

    Et ensuite l'utiliser sur une fonction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    BaseType addition (BaseType a, BaseType b);
    Oui… à la condition que tu ajoutes en plus un paramètre à ta fonction qui puisse lui permettre de savoir quel paramètre il faut utiliser ! C'est en ce sens qu'il ne s'agit pas de code template : il s'agit toujours de la même fonction, qui traite elle-même tous les cas de figure dans la même procédure. Par contre, tu peux effectivement te servir d'un type « union » pour renvoyer un résultat dans le même format que les paramètres d'entrée.

    Ça, ce sont des cas d'école, mais l'un des meilleurs exemples d'utilisation propre d'une union sont les événements « XEvent » de X-Window. Jettes-y un œil si tu le peux.

  6. #6
    Expert confirmé
    Avatar de gerald3d
    Homme Profil pro
    Conducteur de train
    Inscrit en
    Février 2008
    Messages
    2 315
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Conducteur de train
    Secteur : Transports

    Informations forums :
    Inscription : Février 2008
    Messages : 2 315
    Billets dans le blog
    5
    Par défaut
    Citation Envoyé par Obsidian Voir le message
    Oui… à la condition que tu ajoutes en plus un paramètre à ta fonction qui puisse lui permettre de savoir quel paramètre il faut utiliser ! C'est en ce sens qu'il ne s'agit pas de code template : il s'agit toujours de la même fonction, qui traite elle-même tous les cas de figure dans la même procédure. Par contre, tu peux effectivement te servir d'un type « union » pour renvoyer un résultat dans le même format que les paramètres d'entrée.

    Ça, ce sont des cas d'école, mais l'un des meilleurs exemples d'utilisation propre d'une union sont les événements « XEvent » de X-Window. Jettes-y un œil si tu le peux.
    Je comprends tout à fait ta remarque. Je jetterai à l'occasion un oeil sur Xevent.

    Merci à tous de vos commentaires constructifs.

  7. #7
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Il est également courrant d'utiliser des unions "étiquetés" (tagged union) pour garder en mémoire quel champ est utilisé (et ainsi ne pas se tromper).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    enum e_type_union
    {
    	ENTIER;
    	FLOTTANT;
    };
     
    struct s_union_intfloat
    {
    	enum e_type_union type;
    	union u_intfloat {
    		int i;
    		float f;
    	} u;
    };
    Certains langages permettent de faire ça directement.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  8. #8
    Membre chevronné
    Inscrit en
    Décembre 2010
    Messages
    290
    Détails du profil
    Informations forums :
    Inscription : Décembre 2010
    Messages : 290
    Par défaut
    Une autre utilisation que l'on peut notamment trouver dans le K&R est celle de faire un padding automatique, puisque l'union résultante est au moins aussi grande que le type le plus grand qu'elle contient.

    Sinon il me semble que Winsock avait une construction qui utilisait les unions anonymes et qui ressemblait à ça (fortement simplifiée) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    struct sockaddrin_s
    {
       union
       {
           long addr;
           unsigned char b_addr[4]; 
       };
    };
    ce qui permettait d'accéder à une adresse IPv4 sous la forme d'un long (addr) ou de 4 octets.

    Similairement, même si le standard ne le supporte pas (on ne doit normalement jamais lire un champ d'une union qui ne soit pas le dernier champ écrit), j'avais vu un swap little-endian big-endian implémenté comme ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    union
    {
      char bytes[4];
      float f;
    } u, u2; 
     
    u.f = monfloat;
    u2.bytes[0] = u.bytes[3];
    u2.bytes[1] = u.bytes[2];
    u2.bytes[2] = u.bytes[1];
    u2.bytes[3] = u.bytes[0];
    /* u2.f vaut maintenant u.f swappé */

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 3
    Dernier message: 20/05/2015, 17h45
  2. union et struct ?
    Par FoX_*D i E* dans le forum Débuter
    Réponses: 14
    Dernier message: 26/12/2012, 08h38
  3. Réponses: 16
    Dernier message: 26/06/2012, 16h57
  4. Problème avec [b]struct[/b]
    Par Bouziane Abderraouf dans le forum CORBA
    Réponses: 2
    Dernier message: 17/07/2002, 10h25

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo