tags:

views:

80

answers:

4

Hi, 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. Why is it so and is it possible to make is c99 (or c89, c90) compatible? Thanks.

+4  A: 

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;
Svisstack
Thanks, this lead me to solution.
Martin Kopta
+1  A: 

Anonymous unions are a GNU extension, not part of any standard version of the C language. 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...

R..
Care to give a reason for the -1? I think I answered the question completely with the first sentence and a half...
R..
A: 

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.

Martin Kopta
A: 

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.

jer
Thanks for your interest
Martin Kopta