Как проверить, какой тип в настоящее время используется в 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 ответов
есть ли лучшее решение?
нет, решение, которое вы показываете, является лучшим (и единственным). union
s довольно упрощены, не "отслеживать" то, что вы назначили на что. Все что они делают, позволяя использовать один и тот же диапазон памяти для всех своих членов. Они не предоставляют ничего другого, кроме этого, поэтому заключая их в 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);
}
но я советую вам не делать этого.