Intereting Posts

Анонимный союз внутри структуры не в c99?

вот очень упрощенный код проблемы, который у меня есть:

 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;  п.  int_n = i;  return 0;  } 

И я не расстроен:

 $ cc us.c 
 $ cc -std = c99 us.c 
 us.c: 18: 4: предупреждение: декларация ничего не объявляет
 us.c: В функции «main»:
 us.c: 26: 4: error: «struct node» не имеет имени с именем 'int_n'

Использование GCC без опции -std компилирует код выше без каких-либо проблем (и аналогичный код работает очень хорошо), но кажется, что c99 не разрешает эту технику. Почему это так, и возможно ли сделать совместимость c99 (или c89 , c90 )? Благодарю.

Анонимные союзы – это расширение GNU, а не часть стандартной версии языка C. Вы можете использовать -std = gnu99 или что-то подобное для расширений c99 + GNU, но лучше всего писать C и не полагаться на расширения, которые не содержат ничего, кроме синтаксического сахара …

Изменить: Анонимные союзы были добавлены в C11, поэтому теперь они являются стандартной частью языка. Предположительно GCC’s -std=c11 позволяет использовать их.

Я нахожу этот вопрос примерно через полтора года после того, как все это сделали, поэтому я могу дать другой ответ: анонимные структуры не входят в стандарт C99, но они соответствуют стандарту C11. GCC и clang уже поддерживают это (стандарт C11, похоже, отменил эту функцию от Microsoft, и GCC некоторое время поддерживал некоторые расширения MSFT).

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

 $ 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 @@
    объединение {
      struct int_node int_n;
      struct double_node double_n;
 -};
 +} данные;
  };

  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 UPair { struct int_node int_n; struct double_node double_n; }; UPair X; X.int_n.value = 12; 

Другое решение состоит в том, чтобы поместить общее значение заголовка ( enum node_type type ) в каждую структуру и сделать структуру верхнего уровня объединением. Это не совсем «Do not Repeat Yourself», но он избегает как анонимных союзов, так и неудобно выглядящих значений прокси.

 enum node_type { t_int, t_double }; struct int_node { enum node_type type; int value; }; struct double_node { enum node_type type; double value; }; union node { enum node_type type; struct int_node int_n; struct double_node double_n; }; int main(void) { union node n; n.type = t_int; // or n.int_n.type = t_int; n.int_n.value = 10; return 0; } 

Взглянув на 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 указывает, что вещь, в этом случае identifier является необязательным в соответствии с 6.1.