2013-05-18 6 views
16

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

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

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

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

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

ответ

13

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

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

+7

FYI, этот метод называется «помеченным соединением». –

+2

Лучшим решением является использование значений перечисления, а не 1, 2 и т. Д. –

6

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

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

3

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

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

2

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

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

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

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

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

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

Смежные вопросы