si esta estructura va a ser utilizada por algún otro archivo func.c, ¿cómo hacerlo?
Cuando se utiliza un tipo en un archivo (es decir, archivo func.c), debe ser visible. La peor forma de hacerlo es copiarlo y pegarlo en cada archivo fuente que lo necesite.
La forma correcta es ponerlo en un archivo de encabezado e incluir este archivo de encabezado cuando sea necesario.
¿Abriremos un nuevo archivo de encabezado y declararemos la estructura allí e incluiremos ese encabezado en la función c?
Esta es la solución que más me gusta, porque hace que el código sea altamente modular. Codificaría tu estructura como:
#ifndef SOME_HEADER_GUARD_WITH_UNIQUE_NAME
#define SOME_HEADER_GUARD_WITH_UNIQUE_NAME
struct a
{
int i;
struct b
{
int j;
}
};
#endif
Pondría funciones que usan esta estructura en el mismo encabezado (la función que es "semánticamente" parte de su "interfaz").
Y, por lo general, podría nombrar el archivo después del nombre de la estructura y usar ese nombre nuevamente para elegir la definición de guardias de encabezado.
Si necesita declarar una función usando un puntero a la estructura, no necesitará la definición completa de la estructura. Una simple declaración hacia adelante como:
struct a ;
Será suficiente, y disminuye el acoplamiento.
¿O podemos definir la estructura total en el archivo de encabezado e incluirla tanto en source.cy en func.c?
Esta es otra forma, algo más fácil, pero menos modular: algún código que necesite solo su estructura para funcionar, aún tendría que incluir todos los tipos.
En C ++, esto podría conducir a una complicación interesante, pero esto está fuera de tema (sin etiqueta C ++), así que no daré más detalles.
luego, cómo declarar esa estructura como externa en ambos archivos. ?
Tal vez no entiendo el punto, pero Greg Hewgill tiene una muy buena respuesta en su publicación ¿Cómo declarar una estructura en un encabezado que va a ser utilizado por múltiples archivos en c? .
¿Lo escribiremos entonces cómo?
- Si está utilizando C ++, no lo haga.
- Si está utilizando C, debería hacerlo.
La razón es que la administración de estructuras en C puede ser un problema: debe declarar la palabra clave struct en todos los lugares donde se usa:
struct MyStruct ; /* Forward declaration */
struct MyStruct
{
/* etc. */
} ;
void doSomething(struct MyStruct * p) /* parameter */
{
struct MyStruct a ; /* variable */
/* etc */
}
Mientras que un typedef le permitirá escribirlo sin la palabra clave struct.
struct MyStructTag ; /* Forward declaration */
typedef struct MyStructTag
{
/* etc. */
} MyStruct ;
void doSomething(MyStruct * p) /* parameter */
{
MyStruct a ; /* variable */
/* etc */
}
Es importante que aún conserve un nombre para la estructura. Escritura:
typedef struct
{
/* etc. */
} MyStruct ;
simplemente creará una estructura anónima con un nombre typedef-ed, y no podrá declararlo hacia adelante. Así que mantén el siguiente formato:
typedef struct MyStructTag
{
/* etc. */
} MyStruct ;
Por lo tanto, podrá usar MyStruct donde quiera para evitar agregar la palabra clave struct, y aún usar MyStructTag cuando un typedef no funcione (es decir, declaración de reenvío)
Editar:
Se corrigió la suposición incorrecta acerca de la declaración de estructura C99, como lo señaló con razón Jonathan Leffler .
Editar 2018-06-01:
Craig Barnes nos recuerda en su comentario que no es necesario mantener nombres separados para el nombre de la "etiqueta" de la estructura y su nombre de "typedef", como lo hice anteriormente para mayor claridad.
De hecho, el código anterior bien podría escribirse como:
typedef struct MyStruct
{
/* etc. */
} MyStruct ;
IIRC, esto es realmente lo que hace C ++ con su declaración de estructura más simple, detrás de escena, para mantenerlo compatible con C:
// C++ explicit declaration by the user
struct MyStruct
{
/* etc. */
} ;
// C++ standard then implicitly adds the following line
typedef MyStruct MyStruct;
Volviendo a C, he visto ambos usos (nombres separados y los mismos nombres), y ninguno tiene inconvenientes que yo sepa, por lo que usar el mismo nombre hace que la lectura sea más simple si no usa "espacios de nombres" separados de C para estructuras y otros símbolos .
struct b
, pero luego su estructuraa
declara un tipo que no se utiliza (probablemente debería definir un nombre de miembro, tal vezk
, después de la llave de cierre interior y antes del punto y coma.