Comment vérifier quel type est actuellement utilisé dans union?

Disons que nous avons une union:

typedef union someunion {
    int a;
    double b;
} myunion;

Est-il possible de vérifier quel type est dans union après avoir défini par exemple A = 123? Mon approche est d'ajouter cette union à une structure et de définir uniontype à 1 quand c'est int et 2 Quand c'est double.

typedef struct somestruct {
    int uniontype
    myunion numbers;
} mystruct;

Y a-t-il une meilleure solution?

24
demandé sur ahiijny 2013-05-18 14:28:26

5 réponses

Y a-t-il une meilleure solution?

Non, la solution que vous montrez est la meilleure (et la seule). union s sont assez simplistes, ne pas "suivre" ce que vous avez assigné à quoi. Tout ce qu'ils font est de vous permettre de réutiliser la même plage de mémoire pour tous leurs membres. Ils ne fournissent rien d'autre au-delà de cela, donc les enfermer dans un struct et utiliser un champ "type" pour le suivi est précisément la bonne chose à faire.

18
répondu dasblinkenlight 2013-05-18 10:30:00

C ne permet pas automatiquement de savoir quel champ d'une union est actuellement utilisé. (En fait, je crois que la lecture du" mauvais " champ entraîne un comportement défini par l'implémentation.) En tant que tel, il appartient à votre code de garder une trace de celui qui est actuellement utilisé / rempli.

Votre approche pour conserver une variable 'uniontype' distincte est une approche très courante et devrait bien fonctionner.

6
répondu Eric Pi 2013-05-18 10:31:26

Il n'y a aucun moyen d'interroger directement le type actuellement stockés dans un union.

Les seules façons de connaître le type stocké dans un union sont d'avoir un indicateur explicite (comme dans votre exemple mystruct), ou de s'assurer que le contrôle ne circule que vers certaines parties du code lorsque l'union a un élément actif connu.

3
répondu Mankarse 2013-05-18 10:31:48

Selon l'application, s'il s'agit d'un objet de courte durée, vous pourrez peut-être encoder le type dans le flux de contrôle, c'est-à-dire. avoir des blocs/fonctions distincts pour les deux cas

  struct value {
      const char *name;
      myunion u;
  };

  void throwBall(Ball* ball)
  {
     ...
     struct value v;
     v.name = "Ball"; v.u.b = 1.2;
     process_value_double(&v);      //double
     struct value v2;
     v2.name = "Age";
     v2.u.a = 19;
     check_if_can_drive(&v2);       //int
     ...
  }

  void countOranges()
  {
       struct value v;
       v.name = "counter";
       v.u.a = ORANGE;
       count_objects(&v);          //int
  }
2
répondu Adrian Panasiuk 2013-05-18 10:38:52

attention: ce qui suit est juste à des fins d'apprentissage:

Vous pouvez utiliser quelques astuces laides pour le faire (tant que les types de données dans votre union ont des tailles différentes, ce qui est le cas présent):

#include <stdio.h>

typedef union someunion {
  int a;
  double b;
} myunion;

typedef struct somestruct {
  int uniontype;
  myunion numbers;
} mystruct;


#define UPDATE_CONTENT(container, value) if ( \
                                             ((sizeof(value) == sizeof(double)) \
                                              ? (container.uniontype = ((container.numbers.b = value), 2)) \
                                              : (container.uniontype = ((container.numbers.a = value), 1))))

int main()
{
  mystruct my_container;

  UPDATE_CONTENT(my_container, 42);
  printf("%d\n", my_container.uniontype);
  UPDATE_CONTENT(my_container, 37.1);
  printf("%d\n", my_container.uniontype);
  return (0);
}

Mais je vous conseille de ne jamais faire cela.

2
répondu yoones 2013-05-18 10:55:51