302 votes

Pourquoi avons-nous besoin de syndicats C ?

Quand faut-il recourir aux syndicats ? Pourquoi en avons-nous besoin ?

302voto

Adam Rosenfield Points 176408

Les unions sont souvent utilisées pour convertir les représentations binaires des entiers et des flottants :

union
{
  int i;
  float f;
} u;

// Convert floating-point bits to integer:
u.f = 3.14159f;
printf("As integer: %08x\n", u.i);

Bien qu'il s'agisse d'un comportement techniquement indéfini selon la norme C (vous êtes censé ne lire que le champ qui a été écrit le plus récemment), il se comportera de manière bien définie dans pratiquement tous les compilateurs.

Les unions sont aussi parfois utilisées pour implémenter le pseudo-polymorphisme en C, en donnant à une structure une étiquette indiquant le type d'objet qu'elle contient, puis en unissant les types possibles :

enum Type { INTS, FLOATS, DOUBLE };
struct S
{
  Type s_type;
  union
  {
    int s_ints[2];
    float s_floats[2];
    double s_double;
  };
};

void do_something(struct S *s)
{
  switch(s->s_type)
  {
    case INTS:  // do something with s->s_ints
      break;

    case FLOATS:  // do something with s->s_floats
      break;

    case DOUBLE:  // do something with s->s_double
      break;
  }
}

Cela permet à la taille de struct S pour n'être que de 12 octets, au lieu de 28.

180voto

kgiannakakis Points 62727

Les unions sont particulièrement utiles en programmation embarquée ou dans les situations où un accès direct au matériel/à la mémoire est nécessaire. Voici un exemple trivial :

typedef union
{
    struct {
        unsigned char byte1;
        unsigned char byte2;
        unsigned char byte3;
        unsigned char byte4;
    } bytes;
    unsigned int dword;
} HW_Register;
HW_Register reg;

Ensuite, vous pouvez accéder au registre comme suit :

reg.dword = 0x12345678;
reg.bytes.byte3 = 4;

L'endiannité (ordre des octets) et l'architecture du processeur sont bien sûr importantes.

Une autre fonction utile est le modificateur de bits :

typedef union
{
    struct {
        unsigned char b1:1;
        unsigned char b2:1;
        unsigned char b3:1;
        unsigned char b4:1;
        unsigned char reserved:4;
    } bits;
    unsigned char byte;
} HW_RegisterB;
HW_RegisterB reg;

Avec ce code, vous pouvez accéder directement à un seul bit dans le registre/adresse mémoire :

x = reg.bits.b2;

72voto

Snips Points 2940

La programmation de systèmes de bas niveau en est un exemple raisonnable.

IIRC, j'ai utilisé des unions pour décomposer les registres matériels en bits composants. Ainsi, vous pouvez accéder à un registre de 8 bits (comme c'était le cas à l'époque où je faisais ça ;-) en le décomposant en bits.

(J'ai oublié la syntaxe exacte mais...) Cette structure permettrait d'accéder à un registre de contrôle en tant que control_byte ou via les bits individuels. Il serait important de s'assurer que les bits correspondent aux bits de registre corrects pour un endivemnt donné.

typedef union {
    unsigned char control_byte;
    struct {
        unsigned int nibble  : 4;
        unsigned int nmi     : 1;
        unsigned int enabled : 1;
        unsigned int fired   : 1;
        unsigned int control : 1;
    };
} ControlRegister;

42voto

bb-generation Points 421

Je l'ai vu dans quelques bibliothèques comme un remplacement de l'héritage orienté objet.

Par exemple

        Connection
     /       |       \
  Network   USB     VirtualConnection

Si vous voulez que la "classe" de connexion soit l'une ou l'autre des catégories ci-dessus, vous pourriez écrire quelque chose comme :

struct Connection
{
    int type;
    union
    {
        struct Network network;
        struct USB usb;
        struct Virtual virtual;
    }
};

Exemple d'utilisation dans libinfinity : http://git.0x539.de/?p=infinote.git;a=blob;f=libinfinity/common/inf-session.c;h=3e887f0d63bd754c6b5ec232948027cbbf4d61fc;hb=HEAD#l74

40voto

Les unions permettent à des membres de données qui s'excluent mutuellement de partager la même mémoire. Ceci est très important lorsque la mémoire est plus rare, comme dans les systèmes embarqués.

Dans l'exemple suivant :

union {
   int a;
   int b;
   int c;
} myUnion;

Cette union occupera l'espace d'un seul int, plutôt que 3 valeurs int distinctes. Si l'utilisateur définit la valeur de a et ensuite fixer la valeur de b il écraserait la valeur de a puisqu'ils partagent tous deux le même emplacement mémoire.

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