вот очень упрощенный код проблемы, которую я имею:
enum node_type { t_int, t_double }; struct int_node { int value; }; struct double_node { double value; }; struct node { enum node_type type; union { struct int_node int_n; struct double_node double_n; }; }; int main(void) { struct int_node i; i.value = 10; struct node n; n.type = t_int; n.int_n = i; return 0; }
И что я не, undestand - это:
$ cc us.c $ cc -std=c99 us.c us.c:18:4: warning: declaration does not declare anything us.c: In function ‘main’: us.c:26:4: error: ‘struct node’ has no member named ‘int_n’
Используя GCC
без -std
код компиляций опции выше без любых проблем (и подобный код работает вполне прилично), но это кажется этим c99
не разрешает эту технику. То, почему это так, и действительно ли возможно сделать, c99
(или c89
, c90
) совместимый?Спасибо.
Анонимные объединения - это расширение GNU, а не часть какой-либо стандартной версии языка C. Вы можете использовать -std = gnu99 или что-то подобное для расширений c99 + GNU, но лучше написать правильный C и не полагаться на расширения, которые не предоставляют ничего, кроме синтаксического сахара ...
Изменить: Были добавлены анонимные союзы в C11, поэтому теперь они являются стандартной частью языка. Предположительно -std = c11
GCC позволяет вам их использовать.
Ну, решением было назвать экземпляр объединения (который может оставаться анонимным как datatype) и затем использовать это имя в качестве прокси.
$ diff -u old_us.c us.c --- old_us.c 2010-07-12 13:49:25.000000000 +0200 +++ us.c 2010-07-12 13:49:02.000000000 +0200 @@ -15,7 +15,7 @@ union { struct int_node int_n; struct double_node double_n; - }; + } data; }; int main(void) { @@ -23,6 +23,6 @@ i.value = 10; struct node n; n.type = t_int; - n.int_n = i; + n.data.int_n = i; return 0; }
Теперь он компилируется как c99
без каких-либо проблем.
$ cc -std=c99 us.c $
Примечание: я все равно не в восторге от этого решения.
Union должен иметь имя и быть объявлен следующим образом:
union UPair {
struct int_node int_n;
struct double_node double_n;
};
UPair X;
X.int_n.value = 12;
Глядя на 6.2.7.1 C99, я вижу, что идентификатор необязателен:
struct-or-union-specifier:
struct-or-union identifier-opt { struct-declaration-list }
struct-or-union identifier
struct-or-union:
struct
union
struct-declaration-list:
struct-declaration
struct-declaration-list struct-declaration
struct-declaration:
specifier-qualifier-list struct-declarator-list ;
specifier-qualifier-list:
type-specifier specifier-qualifier-list-opt
type-qualifier specifier-qualifier-list-opt
Я облазил весь поиск вдоль и поперек, и не могу найти никаких ссылок на то, что анонимные союзы противоречат спецификации. Весь суффикс -opt указывает на то, что вещь, в данном случае идентификатор
, является необязательной согласно 6.1.