Анонимный союз в структуре не в C99? - PullRequest
49 голосов
/ 12 июля 2010

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

enum node_type {
    t_int, t_double
};

struct int_node {
    int value;
};

struct double_node {
    double value;
};

struct node {
    enum node_type type;
    <b>union {
        struct int_node int_n;
        struct double_node double_n;
    };</b>
};

int main(void) {
    struct int_node i;
    i.value = 10;
    struct node n;
    n.type = t_int;
    n.<b>int_n</b> = i;
    return 0;
}

И что я не понимаю, это:

$ 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) совместимым?Спасибо.

Ответы [ 7 ]

62 голосов
/ 12 июля 2010

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

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

25 голосов
/ 03 февраля 2012

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

5 голосов
/ 12 июля 2010

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

$ 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 
$ 

Примечание. В любом случае, я не доволен этим решением.

2 голосов
/ 11 января 2019

Только для разъяснений по поводу анонима struct или анонима union.

C11

6.7.2.1 Спецификаторы структуры и объединения

неназванный член , спецификатор типа которого является структурным спецификатором с без тега , называется анонимная структура ; неназванный член , спецификатор типа которого является спецификатором объединения с без тега , называется анонимным объединением .Члены анонимной структуры или объединения считаются членами содержащей структуры или объединения.Это применяется рекурсивно, если содержащая структура или объединение также являются анонимными.

C99 Не существует анонимной структуры или объединения

Упрощено: Спецификатор типа Идентификатор { Список объявлений } Теги ;

  • Спецификатор типа : struct или union;
  • Идентификатор : необязательно, пользовательское имя для struct или union;
  • Объявление-список : члены, ваши переменные, анонимные struct и анонимные union
  • Теги : необязательно.Если у вас typedef перед Спецификатором типа , Теги являются псевдонимами, а не Теги .

Он является анонимным struct или анонимным union только в том случае, если у него нет идентификатора и тега, и он существует внутри другого struct или union.

struct s {
    struct { int x; };     // Anonymous struct, no identifier and no tag
    struct a { int x; };   // NOT Anonymous struct, has an identifier 'a'
    struct { int x; } b;   // NOT Anonymous struct, has a tag 'b'
    struct c { int x; } C; // NOT Anonymous struct
};

struct s {
    union { int x; };     // Anonymous union, no identifier and no tag
    union a { int x; };   // NOT Anonymous union, has an identifier 'a'
    union { int x; } b;   // NOT Anonymous union, has a tag 'b'
    union c { int x; } C; // NOT Anonymous union
};

typedef ад: если выtypedef часть тега больше не является тегом, это псевдоним для этого типа.

struct a { int x; } A; // 'A' is a tag
union a { int x; } A;  // 'A' is a tag

// But if you use this way
typedef struct b { int x; } B; // 'B' is NOT a tag. It is an alias to struct 'b'
typedef union b { int x; } B;  // 'B' is NOT a tag. It is an alias to union 'b'

// Usage
A.x = 10; // A tag you can use without having to declare a new variable

B.x = 10; // Does not work

B bb; // Because 'B' is an alias, you have to declare a new variable
bb.x = 10;

В приведенном ниже примере просто измените struct на union, работайте так же.

struct a { int x; }; // Regular complete struct type
typedef struct a aa; // Alias 'aa' for the struct 'a'

struct { int x; } b; // Tag 'b'
typedef struct b bb; // Compile, but unusable.

struct c { int x; } C; // identifier or struct name 'c' and tag 'C'
typedef struct { int x; } d; // Alias 'd'
typedef struct e { int x; } ee; // struct 'e' and alias 'ee'

1 голос
/ 28 марта 2013

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

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;
}
1 голос
/ 12 июля 2010

Глядя на 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.

1 голос
/ 12 июля 2010

Союз должен иметь имя и быть объявлен так:

union UPair {
    struct int_node int_n;
    struct double_node double_n;
};

UPair X;
X.int_n.value = 12;
...