Devuelve una `estructura` de una función en C
Hoy estaba enseñando a un par de amigos cómo usar C struct
s. Uno de ellos preguntó si se podía devolver a struct
desde una función, a lo que respondí: "¡No! En su lugar, devolverías punteros a malloc
ed struct
s dinámicamente".
Viniendo de alguien que hace principalmente C++, esperaba no poder devolver struct
correos 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 return
declaración en conjunción con =
firmar?
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 = a
es que no proporcionaste un tipo completo. struct MyObj b = a
funcionará 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 int
tipo 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;
}
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.