Devuelve una `estructura` de una función en C

Resuelto mmirzadeh asked hace 12 años • 11 respuestas

Hoy estaba enseñando a un par de amigos cómo usar C structs. Uno de ellos preguntó si se podía devolver a structdesde una función, a lo que respondí: "¡No! En su lugar, devolverías punteros a malloced structs dinámicamente".

Viniendo de alguien que hace principalmente C++, esperaba no poder devolver structcorreos electrónicos por valores. En C++ puedes sobrecargar operator =tus objetos y tiene mucho sentido tener una función para devolver tu objeto por valor. En C, sin embargo, no tienes esa opción y eso me hizo pensar en lo que realmente está haciendo el compilador. Considera lo siguiente:

struct MyObj{
    double x, y;
};

struct MyObj foo(){
    struct MyObj a;
    
    a.x = 10;
    a.y = 10;
    
    return a;
}        

int main () {

    struct MyObj a;
    
    a = foo();    // This DOES work
    struct b = a; // This does not work
      
    return 0;
}    

Entiendo por qué struct b = a;no debería funcionar: no puede sobrecargar operator =para su tipo de datos. ¿ Cómo es que eso a = foo();se compila bien? ¿ Significa algo más que struct b = a;? Quizás la pregunta que cabe hacerse es: ¿Qué hace exactamente la returndeclaración en conjunción con =firmar?

mmirzadeh avatar Mar 11 '12 13:03 mmirzadeh
Aceptado

Puedes devolver una estructura desde una función (o usar el =operador) sin ningún problema. Es una parte bien definida del idioma. El único problema struct b = aes que no proporcionaste un tipo completo. struct MyObj b = afuncionará bien. También puede pasar estructuras a funciones: una estructura es exactamente igual que cualquier tipo integrado a efectos de paso de parámetros, valores de retorno y asignación.

Aquí hay un programa de demostración simple que hace las tres cosas: pasa una estructura como parámetro, devuelve una estructura de una función y usa estructuras en declaraciones de asignación:

#include <stdio.h>

struct a {
   int i;
};

struct a f(struct a x)
{
   struct a r = x;
   return r;
}

int main(void)
{
   struct a x = { 12 };
   struct a y = f(x);
   printf("%d\n", y.i);
   return 0;
}

El siguiente ejemplo es prácticamente el mismo, pero utiliza el inttipo integrado con fines de demostración. Los dos programas tienen el mismo comportamiento con respecto al paso por valor para el paso de parámetros, asignación, etc.:

#include <stdio.h>

int f(int x) 
{
  int r = x;
  return r;
}

int main(void)
{
  int x = 12;
  int y = f(x);
  printf("%d\n", y);
  return 0;
}
Carl Norum avatar Mar 11 '2012 07:03 Carl Norum

Al realizar una llamada como a = foo();, el compilador puede enviar la dirección de la estructura de resultados a la pila y pasarla como un puntero "oculto" a la foo()función. Efectivamente, podría convertirse en algo como:

void foo(MyObj *r) {
    struct MyObj a;
    // ...
    *r = a;
}

foo(&a);

Sin embargo, la implementación exacta de esto depende del compilador y/o plataforma. Como señala Carl Norum, si la estructura es lo suficientemente pequeña, podría incluso devolverse completamente a un registro.

Greg Hewgill avatar Mar 11 '2012 07:03 Greg Hewgill