Anonymous union within struct not in c99?

后端 未结 7 999
时光说笑
时光说笑 2020-11-28 11:40

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 valu         


        
相关标签:
7条回答
  • 2020-11-28 12:05

    Well, the solution was to name instance of the union (which can remain anonymous as datatype) and then use that name as a proxy.

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

    $ cc -std=c99 us.c 
    $ 
    

    Note: I am not happy about this solution anyway.

    0 讨论(0)
  • 2020-11-28 12:05

    Another solution is to put the common header value (enum node_type type) into every structure, and make your top-level structure a union. 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;
    }
    
    0 讨论(0)
  • 2020-11-28 12:10

    Just for clarifications about anonymous struct or anonymous union.

    C11

    6.7.2.1 Structure and union specifiers

    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

    Simplified: Type-specifier Identifier { Declaration-list } Tags ;

    • Type-specifier: struct or union;
    • Identifier: optional, your custom name for the struct or union;
    • Declaration-list: members, your variables, anonymous struct and anonymous union
    • Tags: optional. If you have a typedef in front of the Type-specifier, the Tags are alias and not 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 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.

    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.

    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'
    
    
    0 讨论(0)
  • 2020-11-28 12:11

    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;
    
    0 讨论(0)
  • 2020-11-28 12:13

    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. 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).

    0 讨论(0)
  • 2020-11-28 12:23

    Looking at 6.2.7.1 of C99, I'm seeing that the identifier is optional:

    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.

    0 讨论(0)
提交回复
热议问题