53

这是我遇到的非常简化的问题代码:

枚举节点类型 {
    t_int, t_double
};

结构 int_node {
    整数值;
};

结构双节点{
    双倍价值;
};

结构节点{
    枚举节点类型类型;
    联合{
        结构 int_node int_n;
        结构 double_node double_n;
    };
};

诠释主要(无效){
    结构 int_node 我;
    i.value = 10;
    结构节点 n;
    n.type = t_int;
    n. int_n = 我;
    返回0;
}

我不明白的是:

$ cc us.c
$ cc -std=c99 us.c
us.c:18:4:警告:声明未声明任何内容
us.c:在函数'main'中:
us.c:26:4:错误:“结构节点”没有名为“int_n”的成员

使用GCC-std选项编译上面的代码没有任何问题(并且类似的代码工作得很好),但似乎c99 不允许这种技术。为什么会这样,是否有可能使 is c99(或c89, c90)兼容?谢谢。

4

7 回答 7

66

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

编辑: C11 中添加了匿名联合,因此它们现在是该语言的标准部分。大概 GCC-std=c11允许您使用它们。

于 2010-07-12T11:44:25.357 回答
29

我发现这个问题比其他人晚了大约一年半,所以我可以给出不同的答案:匿名结构不在 C99 标准中,但它们在 C11 标准中。GCC 和 clang 已经支持这一点(C11 标准似乎已经从微软那里提升了这个功能,并且 GCC 已经为一些 MSFT 扩展提供了支持)。

于 2012-02-03T19:58:28.490 回答
5

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

$ 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 @@
   联合{
     结构 int_node int_n;
     结构 double_node double_n;
- };
+ } 数据;
 };

 诠释主要(无效){
@@ -23,6 +23,6 @@
   i.value = 10;
   结构节点 n;
   n.type = t_int;
- n.int_n = i;
+ n.data.int_n = i;
   返回0;
 }

现在它编译为c99没有任何问题。

$ cc -std=c99 us.c
$

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

于 2010-07-12T11:51:46.117 回答
5

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

C11

6.7.2.1 结构和联合说明符

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

C99 没有匿名结构或联合

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

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

只有当它没有标识符和标签,并且存在于另一个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
};

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;

下面的示例只是更改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'

于 2019-01-11T20:47:21.333 回答
1

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

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

UPair X;
X.int_n.value = 12;
于 2010-07-12T11:37:09.130 回答
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;
}
于 2013-03-28T16:27:51.183 回答
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 是可选的。

于 2010-07-12T11:52:15.243 回答