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

скажем, мы имеем объединение:

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

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

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

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

Ответы

Ответ 1

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

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

Ответ 2

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

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

Ответ 3

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

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

Ответ 4

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

  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
  }

Ответ 5

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

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

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

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

Ответ 6

Может быть, мой вариант помогает

struct Table
{
    char mas[10];
    int width;
    int high;
    union stat
    {
        int st;
        char v;
    } un;
};


Table tble[2];
strcpy(tble[0].mas, "box");
tble[0].high = 12;
tble[0].width = 14;
tble[0].un.v = 'S';

strcpy(tble[1].mas, "bag");
tble[1].high = 12;
tble[1].width = 14;
tble[1].un.st = 40;

//struct Table *ptbl = &tble[0];
//ptbl++;

for (int i = 0; i < 2; i++)
{
    void *pt = &tble[i].un;
    if(*((char*)pt) == 'S')     
        sort(put_on_bag_line);
    else
        sort(put_on_box_line);
}