Le definizioni della struttura devono essere contenute nel file .h o .c?


102

Ho visto sia le definizioni complete di structs nelle intestazioni che solo le dichiarazioni: c'è qualche vantaggio in un metodo rispetto all'altro?

Se fa la differenza, di solito digito una struttura in questo modo nel file .h

typedef struct s s_t;

modificare

Per essere chiari, le opzioni sono la dichiarazione nel file di intestazione e la definizione nella classe, o sia la dichiarazione che la definizione nel file di intestazione. Entrambi dovrebbero portare alla stessa usabilità, anche se uno è per collegamento, no?


Vedo molti quasi duplicati, ad esempio qui ma nessuna corrispondenza esatta. Per favore correggimi se sbaglio a questo proposito.


2
Vuoi una struttura opaca o non opaca?

4
Nota a margine, gli identificatori con _tsono riservati da POSIX, quindi questa di solito è una cattiva idea. Potresti semplicemente farlo typedef struct toto toto.
Jens Gustedt

Ho visto molti _tusi in altri posti (ad esempio, lighttp, linux) ... e ho aggiunto il prefisso projident_ quindi, non dovrebbe essere un problema, vero?
Aaron Yodaiken

E @WTP, penso che il non opaco sia generalmente considerato migliore e più Cish, no (cosa con l' FILEesempio ecc.). Quindi, non opaco.
Aaron Yodaiken

Se è una struttura non opaca, deve essere inserita in un file di intestazione o il codice non è DRY (non ripetere te stesso).

Risposte:


107

Le strutture private per quel file dovrebbero andare nel file .c, con una dichiarazione nel file .h se vengono utilizzate da qualsiasi funzione nel .h.

Le strutture pubbliche dovrebbero andare nel file .h.


4
Penso di essere più d'accordo con questa risposta. Non si tratta di utilizzare la struttura tramite altri file .c o meno, è se la struttura debba essere considerata pubblica (e quindi accessibile) o meno.
c00kiemon5ter,

@ τεκ Vuoi dire globale localvisibilità? publicnon ha senso in una struttura. Tutti gli struct sono pubblici per impostazione predefinita.
BugShotGG

3
@Geo Papas Questa è una domanda su C. publicnon è una parola chiave in C. Se guardi la risposta di Matthew Slattery sotto puoi vedere come usare solo una dichiarazione in avanti nell'intestazione causa un errore del compilatore quando l'utente cerca di usare i membri di un struttura privata (opaca).
τεκ

68

Entrambi dovrebbero portare alla stessa usabilità, anche se uno è per collegamento, no?

No, non quando si considerano altri file .c che includono la stessa intestazione. Se la definizione della struttura non è visibile al compilatore, i dettagli di quella definizione non possono essere utilizzati. Una dichiarazione senza una definizione (ad esempio solo struct s;) fa sì che il compilatore fallisca se qualcosa cerca di guardare all'interno struct s, pur permettendogli di ad esempio di compilare struct s *foo;(purché foonon venga successivamente dereferenziato).

Confronta queste versioni di api.he 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;          |
                                      | }                               |
                                      +---------------------------------+

Questo client dell'API funziona con entrambe le versioni:

#include "api.h"

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

Questo fa un giro nei dettagli di implementazione:

#include "api.h"

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

che funzionerà con la versione "definizione in intestazione", ma non con la versione "definizione in implementazione", in quanto in quest'ultimo caso il compilatore non ha visibilità del layout della struttura:

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

Quindi, la versione "definizione nell'implementazione" protegge dall'uso improprio accidentale o intenzionale dei dettagli dell'implementazione privata.


3
voglio solo sapere come hai creato quelle finestre di codice e avere ancora il codice evidenziato al loro interno ... manualmente? Questo OP sembra essere uscito usando stackoverflow: '(Qualcun altro può dirmi ...
Mahesha999

Bell'esempio! Grazie!
Victor Haine

Grazie per questo esempio! dereferencing pointer to incomplete typeera esattamente il mio caso!
Timur Fayzrakhmanov

Vorrei solo aggiungere che non tutte le strutture accessibili pubblicamente sono cattive: potresti ad esempio voler consentire all'utente della tua API di inserire i dati e inviarli.
Alexander Torstling

@ Mahesha999, non c'è magia lì. Quindi evidenzia il codice anche se ci metti spazzatura. Si noti che sta cercando di evidenziare l'output della riga di comando più avanti nel post.
Winger Sendon

8

Se la struttura deve essere utilizzata da altre unità di compilazione (file .c), inserirla nel file di intestazione in modo da poter includere tale file di intestazione ovunque sia necessario.

Se la struttura viene utilizzata solo in un'unità di compilazione (file .c), la si inserisce in quel file .c.


3

Il punto è che posizionarlo in un file di intestazione ti consente di utilizzare la struttura (o qualsiasi altra definizione) da più file di origine, semplicemente includendo quel file di intestazione.

Ma se sei sicuro che verrà utilizzato solo da un file sorgente, allora non fa davvero alcuna differenza.



-4

In generale, non penso che faccia una grande differenza se li metti nell'intestazione o nei file sorgente. Tuttavia, se è necessario accedere ai membri di una struttura da più file di origine, è più semplice inserire la struttura in un file di intestazione e includerla da qualsiasi altro file in cui è necessaria la struttura.


8
-1: se ti interessa una buona ingegneria del software (astrazione, modularità, ecc.) Allora in realtà importa dove metti la definizione della struttura
Paul R
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.