c gcc struct c99 unions

¿Unión anónima dentro de struct no en c99?



gcc unions (6)

Aquí hay un código de problema muy simplificado que tengo:

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

Y lo que no entiendo es esto:

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

El uso de GCC sin la opción -std compila el código anterior sin ningún problema (y el código similar funciona bastante bien), pero parece que c99 no permite esta técnica. ¿Por qué es así y es posible hacer que c99 (o c89 , c90 ) sea compatible? Gracias.


Bueno, la solución fue nombrar la instancia de la unión (que puede permanecer anónima como tipo de datos) y luego usar ese nombre como 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; }

Ahora se compila como c99 sin ningún problema.

$ cc -std=c99 us.c $

Nota: de todos modos, no estoy contento con esta solución.


Estoy encontrando esta pregunta aproximadamente un año y medio después que todos los demás, por lo que puedo dar una respuesta diferente: las estructuras anónimas no están en el estándar C99, pero están en el estándar C11. GCC y clang ya lo admiten (el estándar C11 parece haber eliminado la función de Microsoft, y GCC ha brindado soporte para algunas extensiones de MSFT durante algún tiempo).


La Unión debe tener un nombre y declararse así:

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


Los sindicatos anónimos son una extensión de GNU, que no forma parte de ninguna versión estándar del lenguaje C. Puede usar -std = gnu99 o algo así para las extensiones c99 + GNU, pero lo mejor es escribir C propiamente dicha y no confiar en extensiones que proporcionan nada más que azúcar sintáctico ...

Editar: Se agregaron uniones anónimas en C11, por lo que ahora son una parte estándar del idioma. Presumiblemente GCC''s -std=c11 te permite usarlos.


Mirando 6.2.7.1 de C99, estoy viendo que el identificador es opcional:

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

He estado buscando y buscando, y no puedo encontrar ninguna referencia a uniones anónimas que estén en contra de las especificaciones. El sufijo -opt completo indica que la cosa, en este caso el identifier es opcional de acuerdo con 6.1.


Otra solución es colocar el valor de encabezado común ( enum node_type type ) en cada estructura y hacer que su estructura de nivel superior sea una unión. No es exactamente "Do not Repeat Yourself", pero evita las uniones anónimas y los valores de proxy incómodos.

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