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