struct中的匿名联合不在c99中?

时间:2010-07-12 11:35:41

标签: c gcc struct c99 unions

这里有一个非常简化的问题代码:

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

我不明白的是:

$ 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(或c89c90)兼容?感谢。

7 个答案:

答案 0 :(得分:60)

匿名联合是GNU扩展,不是C语言的任何标准版本的一部分。对于c99 + GNU扩展,你可以使用-std = gnu99或类似的东西,但是最好编写适当的C而不是依赖于只提供语法糖的扩展......

编辑:匿名工会已在C11中添加,因此它们现在是该语言的标准部分。据推测,GCC的-std=c11允许你使用它们。

答案 1 :(得分:25)

我发现这个问题大约在其他人做了一年半之后,所以我可以给出一个不同的答案:匿名结构不符合C99标准,但它们符合C11标准。 GCC和clang已经支持这一点(C11标准似乎已经取消了微软的功能,GCC已经为一些MSFT扩展提供了一段时间的支持。)

答案 2 :(得分:5)

嗯,解决方案是命名union的实例(可以作为数据类型保持匿名),然后使用该名称作为代理。

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

注意:无论如何,我对此解决方案并不满意。

答案 3 :(得分:2)

仅用于说明匿名struct或匿名union

C11

6.7.2.1结构和联合说明符

  

未命名成员,其类型说明符是具有以下内容的结构说明符   没有标签称为匿名结构未命名成员,其类型   说明符是带有没有标签的联合说明符,称为匿名   联盟。匿名结构或联合的成员被认为   成为包含结构或联合的成员。这适用   如果包含的结构或联合也是匿名的,则递归地进行。

C99 没有匿名结构或联合

简化:类型说明符 标识符 { 声明列表 } 标签 ;

  • 类型说明符structunion;
  • 标识符:可选,您的structunion的自定义名称;
  • 声明列表:成员,您的变量,匿名struct和匿名union
  • 标签:可选。如果 Type-specifier 前面有一个typedef,则 Tags 是别名而不是 Tags

只有匿名标识符structunion内没有标识符和标签,它才是匿名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的{​​{1}}更改为相同的方式。

union

答案 4 :(得分:1)

Union必须有一个名字并且声明如下:

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

UPair X;
X.int_n.value = 12;

答案 5 :(得分:1)

查看C99的6.2.7.1,我发现标识符是可选的:

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。

答案 6 :(得分:1)

另一种解决方案是将公共标头值(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;
}