Как проверить, какой тип в настоящее время используется в union?

допустим, у нас есть союз:

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

можно ли проверить, какой тип находится в union после того, как я установил, например, a=123? Мой подход состоит в том, чтобы добавить это объединение в некоторую структуру и установить uniontype в 1, когда это int и 2, когда это double.

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

есть ли лучшее решение?

5 ответов


есть ли лучшее решение?

нет, решение, которое вы показываете, является лучшим (и единственным). unions довольно упрощены, не "отслеживать" то, что вы назначили на что. Все что они делают, позволяя использовать один и тот же диапазон памяти для всех своих членов. Они не предоставляют ничего другого, кроме этого, поэтому заключая их в struct и использование поля " тип " для отслеживания-это именно то, что нужно сделать.


C не отслеживает автоматически, какое поле в объединении используется в данный момент. (На самом деле, я считаю, что чтение из "неправильного" поля приводит к реализации определенного поведения.) Таким образом, ваш код должен отслеживать, какой из них в настоящее время используется / заполняется.

ваш подход к сохранению отдельной переменной "uniontype" является очень распространенным подходом к этому и должен хорошо работать.


нет способа напрямую запросить тип, хранящийся в настоящее время в union.

единственные способы узнать тип, хранящийся в union должны иметь явный флаг (как в вашем mystruct example), или чтобы гарантировать, что управление течет только к определенным частям кода, когда объединение имеет известный активный элемент.


в зависимости от приложения, если это недолговечный объект, вы можете кодировать тип в потоке управления, т. е. есть отдельные блоки/функции для обоих случаев

  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
  }

предупреждение: следующее только для целей обучения:

вы можете использовать некоторые уродливые трюки для этого (если типы данных в вашем союзе имеют разные размеры, что является настоящим случаем):

#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);
}

но я советую вам не делать этого.