简体   繁体   English

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

[英]Anonymous union within struct not in c99?

here is very simplified code of problem I have: 这里是我所遇到的非常简化的问题代码:

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

And what I don't undestand is this: 我不明白的是:

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

Using GCC without -std option compiles code above without any problems (and the similar code is working pretty well), but it seems that c99 does not permit this technique. 使用没有-std选项的GCC编译上面的代码没有任何问题(类似的代码工作得很好),但似乎c99不允许这种技术。 Why is it so and is it possible to make is c99 (or c89 , c90 ) compatible? 为什么这样可以使c99 (或c89c90 )兼容? Thanks. 谢谢。

Anonymous unions are a GNU extension, not part of any standard version of the C language. 匿名联合是GNU扩展,不是任何标准版本的C语言的一部分。 You can use -std=gnu99 or something like that for c99+GNU extensions, but it's best to write proper C and not rely on extensions which provide nothing but syntactic sugar... 对于c99 + GNU扩展,你可以使用-std = gnu99或类似的东西,但最好写出适当的C而不依赖于只提供语法糖的扩展......

Edit: Anonymous unions were added in C11, so they are now a standard part of the language. 编辑:匿名工会在C11中添加,因此它们现在是该语言的标准部分。 Presumably GCC's -std=c11 lets you use them. 据推测,GCC的-std=c11可以让你使用它们。

I'm finding this question about a year and a half after everybody else did, so I can give a different answer: anonymous structs are not in the C99 standard, but they are in the C11 standard. 我发现这个问题大约在其他人做了一年半之后,所以我可以给出一个不同的答案:匿名结构不符合C99标准,但它们符合C11标准。 GCC and clang already support this (the C11 standard seems to have lifted the feature from Microsoft, and GCC has provided support for some MSFT extensions for some time). GCC和clang已经支持这一点(C11标准似乎已经取消了微软的功能,并且GCC已经为一些MSFT扩展提供了一段时间的支持)。

Well, the solution was to name instance of the union (which can remain anonymous as datatype) and then use that name as a proxy. 好吧,解决方案是命名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;
 }

Now it compiles as c99 without any problems. 现在它编译为c99没有任何问题。

$ cc -std=c99 us.c 
$

Note: I am not happy about this solution anyway. 注意:无论如何,我对这个解决方案并不满意。

Just for clarifications about anonymous struct or anonymous union . 仅用于澄清匿名struct或匿名union

C11 C11

6.7.2.1 Structure and union specifiers 6.7.2.1结构和联合说明符

An unnamed member whose type specifier is a structure specifier with no tag is called an anonymous structure ; 类型说明符是没有标记的结构说明符的未命名成员称为匿名结构 ; an unnamed member whose type specifier is a union specifier with no tag is called an anonymous union . 一个未命名的成员,其类型说明符是一个没有标记的联合说明符,称为匿名联合 The members of an anonymous structure or union are considered to be members of the containing structure or union. 匿名结构或联合的成员被视为包含结构或联合的成员。 This applies recursively if the containing structure or union is also anonymous. 如果包含的结构或联合也是匿名的,则递归应用。

C99 There are no anonymous struct or union C99 没有匿名结构或联合

Simplified: Type-specifier Identifier { Declaration-list } Tags ; 简化: 类型说明 符标识符 { 声明列表 } 标记 ;

  • Type-specifier : struct or union ; 类型说明符structunion ;
  • Identifier : optional, your custom name for the struct or union ; 标识符 :可选, structunion自定义名称;
  • Declaration-list : members, your variables, anonymous struct and anonymous union 声明列表 :成员,变量,匿名struct和匿名union
  • Tags : optional. 标签 :可选。 If you have a typedef in front of the Type-specifier , the Tags are alias and not Tags . 如果在Type-specifier前面有typedef ,则Tags是别名而不是Tags

It is a anonymous struct or anonymous union only if it have no identifier and no tag, and exist inside another struct or union . 它只是一个匿名struct或匿名union只有它没有标识符和标记,并且存在于另一个structunion内部。

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 hell: if you have a typedef the tag part is not a tag anymore, it is alias for that type. typedef hell:如果你有一个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;

The example bellow just change struct for union , work the same way. 下面的例子只是改变了union struct ,工作方式相同。

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'

Another solution is to put the common header value ( enum node_type type ) into every structure, and make your top-level structure a union. 另一种解决方案是将公共标头值( enum node_type type )放入每个结构中,并使您的顶级结构成为联合。 It's not exactly "Don't Repeat Yourself", but it does avoid both anonymous unions and uncomfortable looking proxy values. 它并不完全是“不要重复自己”,但它确实避免了匿名联合和不舒服的代理值。

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

Union must have a name and be declared like this: 联盟必须有一个名称,并声明如下:

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

UPair X;
X.int_n.value = 12;

Looking at 6.2.7.1 of C99, I'm seeing that the identifier is optional: 查看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

I've been up and down searching, and cannot find any reference to anonymous unions being against the spec. 我一直在寻找,并且找不到任何匿名工会违反规范的提法。 The whole -opt suffix indicates that the thing, in this case identifier is optional according to 6.1. 整个-opt后缀表示该东西,在这种情况下identifier是6.1的可选项。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM