¿Qué tienen de especial las estructuras?

Sé que en C no podemos devolver una matriz desde una función, sino un puntero a una matriz. Pero quiero saber qué es lo especial de las structs que las hace capaces de ser devueltas por las funciones aunque puedan contener matrices.

¿Por qué la struct envoltura hace que el siguiente progtwig sea válido?

 #include  struct data { char buf[256]; }; struct data Foo(const char *buf); int main(void) { struct data obj; obj = Foo("This is a sentence."); printf("%s\n", obj.buf); return 0; } struct data Foo(const char *buf) { struct data X; strcpy(X.buf, buf); return X; } 

Una mejor manera de hacer la misma pregunta sería “qué tiene de especial los arreglos”, ya que son los arreglos los que tienen un manejo especial adjunto, no las struct .

El comportamiento de las matrices de paso y retorno mediante punteros se remonta a la implementación original de C. Las matrices “decaen” a los punteros, causando una gran confusión, especialmente entre las personas nuevas en el idioma. Las estructuras, por otro lado, se comportan como los tipos incorporados, como int s, double s, etc. Esto incluye cualquier matriz incrustada en la struct , excepto los miembros de matriz flexible , que no se copian.

En primer lugar, para citar C11 , capítulo §6.8.6.4, statement de return , ( énfasis mío )

Si se ejecuta una statement de return con una expresión, el valor de la expresión se devuelve al llamante como el valor de la expresión de llamada de función.

Devolver una variable de estructura es posible (y correcto), porque se devuelve el valor de la estructura. Esto es similar a devolver cualquier tipo de datos primitivos (devolver int , por ejemplo).

Por otro lado, si devuelve una matriz , utilizando el return , esencialmente devuelve la dirección del primer elemento de la matriz NOTA , que se vuelve inválida en el llamador si la matriz era local a las funciones llamadas. Por lo tanto, no es posible devolver la matriz de esa manera.

Entonces, TL; DR , no hay nada especial con las struct , la especialidad es en arreglos .


NOTA:

Citando C11 nuevo, capítulo §3.3.2.1, ( mi énfasis )

Excepto cuando es el operando del operador sizeof , el operador _Alignof , o el operador unario & , o es un literal de cadena utilizado para inicializar una matriz, una expresión que tiene el tipo ” matriz de tipo ” se convierte en una expresión con escriba “puntero a tipo” que apunta al elemento inicial del objeto de matriz y no es un valor de l. […]

No hay nada especial en los tipos de struct ; es que hay algo especial en los tipos de matriz que evita que se devuelvan directamente desde una función.

Una expresión de struct se trata como una expresión de cualquier otro tipo no de matriz; se evalúa al valor de la struct . Así que puedes hacer cosas como

 struct foo { ... }; struct foo func( void ) { struct foo someFoo; ... return someFoo; } 

La expresión someFoo evalúa el valor del objeto struct foo ; los contenidos del objeto se devuelven desde la función (incluso si esos contenidos contienen matrices).

Una expresión de matriz se trata de manera diferente; si no es el operando de sizeof o unary & operator, o si no se utiliza un literal de cadena para inicializar otra matriz en una statement, la expresión se convierte (“decae”) del tipo “matriz de T ” a ” puntero a T “, y el valor de la expresión es la dirección del primer elemento.

Por lo tanto, no puede devolver una matriz por valor desde una función, porque cualquier referencia a una expresión de matriz se convierte automáticamente en un valor de puntero.

Las estructuras tienen miembros de datos públicos de forma predeterminada, por lo que es posible en caso de que la estructura tenga acceso a los datos en main pero no en el caso de la clase. Por lo tanto, la envoltura de la estructura es válida.