¿Deben ir las definiciones de estructuras en archivos .ho .c?

102

He visto definiciones completas de structs en encabezados y solo declaraciones. ¿Hay alguna ventaja de un método sobre el otro?

Si hace una diferencia, generalmente escribo def una estructura como esa en el .h

typedef struct s s_t;

Editar

Para ser claros, las opciones son declaración en el archivo de encabezado y definición en la clase, o tanto declaración como definición en el archivo de encabezado. Ambos deberían resultar en la misma usabilidad, incluso si uno es por enlace, ¿no es así?


Veo muchos casi duplicados, por ejemplo, aquí, pero sin coincidencias exactas. Por favor corríjame si me equivoco en este sentido.

Aaron Yodaiken
fuente
2
¿Quieres una estructura opaca o no opaca?
4
Nota al margen, los identificadores con _testán reservados por POSIX, por lo que esto suele ser una mala idea. Podrías simplemente hacer typedef struct toto toto.
Jens Gustedt
He visto muchos _tusos en otros lugares (por ejemplo, lighttp, linux) ... y prefijo cosas con projident_ entonces, eso no debería ser un problema, ¿verdad?
Aaron Yodaiken
Y @WTP, creo que lo no opaco generalmente se considera mejor y más Cish, no (con el FILEejemplo, etc.). Entonces, no opaco.
Aaron Yodaiken
Si es una estructura no opaca, tiene que ir en un archivo de encabezado, o su código no es DRY (no lo repita).

Respuestas:

107

Las estructuras privadas para ese archivo deben ir en el archivo .c, con una declaración en el archivo .h si son utilizadas por alguna función en .h.

Las estructuras públicas deben ir en el archivo .h.

τεκ
fuente
4
Creo que estoy más de acuerdo con esta respuesta. No se trata de usar la estructura a través de otros archivos .c o no, se trata de si la estructura debe considerarse pública (y por tanto, accesible) o no.
c00kiemon5ter
@ τεκ ¿Quieres decir globaly localvisibilidad? publicno tiene sentido en una estructura. Todas las estructuras son públicas de forma predeterminada.
BugShotGG
3
@Geo Papas Esta es una pregunta sobre C. publicno es una palabra clave en C. Si observa la respuesta de Matthew Slattery a continuación, puede ver cómo usar solo una declaración directa en el encabezado causa un error del compilador cuando el usuario intenta usar miembros de un estructura privada (opaca).
τεκ
68

Ambos deberían resultar en la misma usabilidad, incluso si uno es por enlace, ¿no es así?

No, no cuando considera otros archivos .c que incluyen el mismo encabezado. Si la definición de la estructura no es visible para el compilador, los detalles de esa definición no se pueden utilizar. Una declaración sin una definición (por ejemplo, simplemente struct s;) hace que el compilador falle si algo intenta mirar dentro struct s, mientras que aún le permite, por ejemplo, compilar struct s *foo;(siempre que foono se desreferencia más tarde).

Compare estas versiones de api.hy api.c:

Definition in header:                 Definition in implementation:
+---------------------------------+   +---------------------------------+
| struct s {                      |   | struct s;                       |
|     int internal;               |   |                                 |
|     int other_stuff;            |   | extern void                     |
| };                              |   | api_func(struct s *foo, int x); |
|                                 |   +---------------------------------+
| extern void                     |   +---------------------------------+
| api_func(struct s *foo, int x); |   | #include "api.h"                |
+---------------------------------+   |                                 |
+---------------------------------+   | struct s {                      |
| #include "api.h"                |   |     int internal;               |
|                                 |   |     int other_stuff;            |
| void                            |   | };                              |
| api_func(struct s *foo, int x)  |   |                                 |
| {                               |   | void                            |
|     foo->internal = x;          |   | api_func(struct s *foo, int x)  |
| }                               |   | {                               |
+---------------------------------+   |     foo->internal = x;          |
                                      | }                               |
                                      +---------------------------------+

Este cliente de la API funciona con cualquiera de las versiones:

#include "api.h"

void good(struct s *foo)
{
    api_func(foo, 123);
}

Este hurga en los detalles de implementación:

#include "api.h"

void bad(struct s *foo)
{
    foo->internal = 123;
}

que funcionará con la versión "definición en encabezado", pero no con la versión "definición en implementación", ya que en el último caso el compilador no tiene visibilidad del diseño de la estructura:

$ gcc -Wall -c bad.c
bad.c: In function 'bad':
bad.c:5: error: dereferencing pointer to incomplete type
$

Por lo tanto, la versión de "definición en implementación" protege contra el uso indebido accidental o deliberado de detalles de implementación privados.

Matthew Slattery
fuente
3
solo quiere saber cómo creó esas ventanas de código y aún tiene el código resaltado dentro de ellas ... ¿manualmente? Este OP parece haberse ido usando stackoverflow: '(¿Alguien más puede decirme ...?
Mahesha999
Buen ejemplo! ¡Gracias!
Victor Haine
¡Gracias por tal ejemplo! dereferencing pointer to incomplete typefue exactamente mi caso!
Timur Fayzrakhmanov
Solo me gustaría agregar que no todas las estructuras de acceso público son malas: por ejemplo, es posible que desee permitir que el usuario de su API complete los datos y los envíe.
Alexander Torstling
@ Mahesha999, no hay magia ahí. SO resalta el código incluso si pones basura en él. Observe que intenta resaltar la salida de la línea de comando más adelante en la publicación.
Extremo Sendon
8

Si la estructura va a ser utilizada por otras unidades de compilación (archivos .c), colóquela en el archivo de encabezado para que pueda incluir ese archivo de encabezado donde sea necesario.

Si la estructura solo se usa en una unidad de compilación (archivo .c), colóquela en ese archivo .c.

nos
fuente
3

El punto es que colocarlo en un archivo de encabezado le permite usar la estructura (o cualquier otra definición) de varios archivos de origen, con solo incluir ese archivo de encabezado.

Pero si está seguro de que solo se usará desde un archivo fuente, entonces realmente no hace ninguna diferencia.

Jonathan Wood
fuente
-4

Generalmente, no creo que haya una gran diferencia si los coloca en el encabezado o en los archivos fuente. Sin embargo, si necesita acceder a los miembros de una estructura desde varios archivos de origen, es más fácil colocar la estructura en un archivo de encabezado e incluirlo desde cualquier otro archivo donde se necesite la estructura.

Frxstrem
fuente
8
-1: si le importa una buena ingeniería de software (abstracción, modularidad, etc.), entonces realmente importa dónde coloque la definición de estructura
Paul R