首页 文章

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

提问于
浏览
42

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

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 )兼容?谢谢 .

6 回答

  • 1

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

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

  • 2

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

  • 4

    好吧,解决方案是命名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 
    $
    

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

  • 23

    联盟必须有一个名称,并声明如下:

    union UPair {
        struct int_node int_n;
        struct double_node double_n;
    };
    
    UPair X;
    X.int_n.value = 12;
    
  • 1

    另一种解决方案是将公共标头值( enum node_type type )放入每个结构中,并使您的顶级结构成为一个联合 . 它不完全是"Don't Repeat Yourself",但它确实避免了匿名联合和不舒服的代理值 .

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

    查看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后缀表示根据6.1,在这种情况下 identifier 是可选的 .

相关问题