retorno - retornar un string en una funcion en c
¿Cómo devolver una estructura anónima en C? (6)
Probando un código, me di cuenta de que compila el siguiente código:
struct { int x, y; } foo(void) {
}
Parece que estamos definiendo una función llamada foo
que devuelve una struct
anónima.
Ahora, mi pregunta es: ¿solo compila con mi compilador o es este C legal (99)? Si es así, ¿cuál es la sintaxis correcta para una declaración de devolución y cómo puedo asignar correctamente el valor devuelto a una variable?
Aquí hay una forma de devolver estructuras anónimas en C ++ 14 sin ningún tipo de piratería que acabo de descubrir.
(C ++ 11 debería ser suficiente, supongo)
En mi caso, una función intersect()
devuelve std::pair<bool, Point>
que no es muy descriptivo, así que decidí crear un tipo personalizado para el resultado.
Podría haber hecho una struct
separada, pero no valía, ya que solo la necesitaría para este caso especial; es por eso que utilicé una estructura anónima.
auto intersect(...params...) {
struct
{
Point point;
bool intersects = false;
} result;
// do stuff...
return result;
}
Y ahora, en lugar de lo feo
if (intersection_result.first) {
Point p = intersection_result.second
Puedo usar el aspecto mucho mejor:
if (intersection_result.intersects) {
Point p = intersection_result.point;
Esto funciona en mi versión de GCC, pero parece un truco total. Tal vez sea útil en el código autogenerado en el que no desea lidiar con la complejidad adicional de generar etiquetas de estructura únicas, pero me estoy estirando para llegar incluso a esa racionalización.
struct { int x,y; }
foo(void) {
typeof(foo()) ret;
ret.x = 1;
ret.y = 10;
return ret;
}
main()
{
typeof(foo()) A;
A = foo();
printf("%d %d/n", A.x, A.y);
}
Además, depende de que typeof () esté presente en el compilador: GCC y LLVM parecen ser compatibles, pero estoy seguro de que muchos compiladores no lo hacen.
Esto funciona hasta la versión más nueva de GCC. Es particularmente útil para crear matrices dinámicas con macros. Por ejemplo:
#define ARRAY_DECL(name, type) struct { int count; type *array; } name
Luego puede hacer la matriz con realloc, etc. Esto es útil porque entonces puede crear una matriz dinámica con CUALQUIER tipo, y hay una manera de hacer todas ellas. De lo contrario, terminarías usando muchos void *
y luego escribirías funciones para realmente recuperar los valores con moldes y demás. Puede atajar todo esto con macros; esa es su belleza
La estructura que estás devolviendo no es una estructura anónima. El estándar C define una estructura anónima como miembro de otra estructura que no usa una etiqueta. Lo que estás devolviendo es una estructura sin una etiqueta, pero como no es miembro, no es anónimo. Gcc usa el nombre <anonymous> para indicar una estructura sin una etiqueta.
Digamos que intentas declarar una estructura idéntica en la función.
struct { int x, y; } foo( void )
{
return ( struct { int x, y; } ){ 0 } ;
}
gcc se queja de ello: se esperaban tipos incompatibles al devolver el tipo ''struct <anonymous>'' pero ''struct <anonymous>''
Aparentemente los tipos no son compatibles. Mirando en el estándar vemos que:
6.2.7 Tipo compatible y tipo compuesto
1: dos tipos tienen tipo compatible si sus tipos son los mismos. Las reglas adicionales para determinar si dos tipos son compatibles se describen en 6.7.2 para especificadores de tipo, en 6.7.3 para calificadores de tipo y en 6.7.6 para declaradores. Además, dos tipos de estructura, unión o enumerados declarados en unidades de traducción separadas son compatibles si sus etiquetas y miembros satisfacen los siguientes requisitos: Si uno se declara con una etiqueta, el otro se declarará con la misma etiqueta. Si ambos se completan en cualquier lugar dentro de sus respectivas unidades de traducción, se aplicarán los siguientes requisitos adicionales : habrá una correspondencia uno a uno entre sus miembros, de modo que cada par de miembros correspondientes se declare con tipos compatibles; si un miembro del par se declara con un especificador de alineación, el otro se declara con un especificador de alineación equivalente; y si un miembro del par se declara con un nombre, el otro se declara con el mismo nombre. Para dos estructuras, los miembros correspondientes se declararán en el mismo orden. Para dos estructuras o uniones, los campos de bits correspondientes deben tener el mismo ancho. Para dos enumeraciones, los miembros correspondientes tendrán los mismos valores.
La segunda parte en negrita explica que si ambas estructuras están sin la etiqueta, como en este ejemplo, tienen que seguir los requisitos adicionales enumerados a continuación de esa parte, lo que hacen. Pero si observa la primera parte en negrita, tienen que estar en unidades de traducción separadas, las estructuras en el ejemplo no lo son. Entonces no son compatibles y el código no es válido.
Es imposible hacer que el código sea correcto, ya que si declaras una estructura y la usas en esta función, debes usar una etiqueta, lo que infringe la regla de que ambas tienen estructuras con la misma etiqueta:
struct t { int x, y; } ;
struct { int x, y; } foo( void )
{
struct t var = { 0 } ;
return var ;
}
De nuevo gcc se queja: tipos incompatibles cuando se esperaba devolver el tipo ''struct t'' pero ''struct <anonymous>''
O podrías crear recursión infinita:
struct { int x, y; } foo(void) {
return foo();
}
Lo cual creo que es completamente legal.
Probablemente no pueda return
explícitamente algún valor agregado de su función (a menos que use un tipo de extensión para obtener el tipo del resultado).
La moraleja de la historia es que incluso si puedes declarar una función devolviendo una struct
anónima , prácticamente nunca deberías hacer eso .
En su lugar, nombre la struct
y el código:
struct twoints_st { int x; int y; };
struct twoints_st foo (void) {
return ((struct twoints_st) {2, 3});
};
Observe que está sintácticamente bien, pero en general es un comportamiento indefinido en la ejecución, para tener una función sin return
(por ejemplo, podría llamar a exit
dentro de ella). Pero ¿por qué querrías codificar el (probablemente legal):
struct { int xx; int yy; } bizarrefoo(void) { exit(EXIT_FAILURE); }