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

Mar*_*tin 49 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(或c89,c90)兼容?谢谢.

R..*_*R.. 62

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

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


bk.*_*bk. 25

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

  • 具有讽刺意味的是,匿名结构和联合所提供的语义可以在Dennis Ritchie的1974 C编译器中获得,我认为gcc在C89标准之前的几天就支持匿名结构和联合.有些人似乎认为这是一个新功能,但它只是代表了一种永远不会丢失的重获能力. (8认同)

Mar*_*tin 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 
$ 

注意:无论如何,我对这个解决方案并不满意.

  • 你应该感到高兴!它是访问union成员的标准方法,保证自1970年1月1日起可以与任何C编译器一起使用. (3认同)
  • 我意识到这是一个非常古老的帖子,但复制实际代码而不是diff补丁更具可读性. (3认同)
  • 它稍微讨论了代码,不知道为什么它不包含在K&R C中,对我来说似乎是一个简单而有用的功能......无论如何我使用相同的代理方法但定义宏以避免所有的输入. (2认同)
  • @binki或许我们需要一个DiffOverflow,其中人们发布代码和答案的片段包含改善它们的差异(可能基于彼此):) (2认同)

Und*_*ior 5

只是为了澄清匿名struct或匿名union

C11

6.7.2.1 结构和联合说明符

类型说明符是没有标记的结构说明符 的未命名成员称为匿名结构;类型说明符是没有标记的联合说明符的未命名成员称为匿名联合。匿名结构或联合的成员被认为是包含结构或联合的成员。如果包含结构或联合也是匿名的,这将递归地适用。

C99 没有匿名结构体或联合体

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

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

只有当它没有标识符和标签,并且存在于另一个or 中时,它才是匿名的struct或匿名的。unionstructunion

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
};
Run Code Online (Sandbox Code Playgroud)

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;
Run Code Online (Sandbox Code Playgroud)

下面的示例只是更改structunion,以相同的方式工作。

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'

Run Code Online (Sandbox Code Playgroud)

  • 你的标签是倒着的。紧接在“struct”或“union”之后的标识符是标签。对于`struct a { int x; } A;`,`a` 就是标签;`A` 是该 `struct` 的_变量_。一旦你正确了,那么 `typedef` 就没有特殊情况了,因为 `a` 仍然是标签;只是“A”变成了_type_而不是变量。 (3认同)

Svi*_*ack 1

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

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

UPair X;
X.int_n.value = 12;
Run Code Online (Sandbox Code Playgroud)

  • 不是在 C11 中,而是在 C99 中。但自从它发布以来我们已经过了三年了,也许是时候开始传递 -std=c11 了:)。 (3认同)
  • 您的代码示例是 C++ 语言,而不是 C 语言。`union UPair` 不会在 C 语言中声明 `UPair` 类型。标签和类型的命名空间在 C 中是分开的,但在 C++ 中却不是。 (2认同)