retorno - ¿Cómo devolver una estructura anónima en C?




retornar una estructura en c (4)

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.


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.







return-type