EDIT: cambiato foo_t a foo come typename perché POSIX riserva tipi che terminano in 't EDIT: cambiato _foo_s per foo_s causa C sostiene nomi che iniziano con un carattere di sottolineaturacontrastanti dichiarazione anticipata anonimo nell'intestazione
Sono perplesso su ciò che il modo migliore è quello di avere il seguente allo stesso tempo:
- l'attuazione biblioteca vede i membri struct ma gli utenti della biblioteca Non
- il compilatore controlla se la definizione della funzione nell'intestazione corrisponde l'attuazione
- uso C99
Il mio primo tentativo di questo è stato quello di effettuare le seguenti operazioni:
foo.h (guardie di inclusione omesse per brevità):
typedef struct foo_s foo;
struct foo_s;
foo* foo_create(void);
void foo_do_something(foo *foo);
foo.c:
#include "foo.h"
struct foo_s {
/* some_hidden_members */
};
foo* foo_create() {
/* allocate memory etc */
}
void foo_do_something(foo *foo) {
/* do something with foo */
}
Questo sembra funzionare con gcc. Chiunque includa foo.h
vede solo la dichiarazione anticipata anonima e il layout reale di struct foo_s
è noto solo in foo.c
.
Ho iniziato ad annusare qualcosa di strano con quanto sopra quando ho provato ad usare include-che-usi che usa clang. Quando l'ho usato per controllare foo.c
mi ha informato che foo.h
non deve contenere la dichiarazione in avanti di struct foo_s
. Ho pensato che fosse un bug in iwyu perché ovviamente questo non sarebbe un problema per nessuno che includesse lo foo.h
.
A questo punto fammi venire alla mia seconda richiesta dall'inizio. foo.c
include foo.h
in modo che il compilatore possa assicurarsi che ogni funzione dichiarata in foo.h
corrisponda all'implementazione in foo.c
. Penso di aver bisogno di questo perché ho riscontrato errori di segmentazione troppo spesso perché la firma della funzione della mia implementazione non corrispondeva a quella nell'intestazione utilizzata dall'altro codice.
In seguito ho provato la compilazione del codice con clang (compilo con -Wall -Wextra -Werror
) ed è stato informato che:
error: redefinition of typedef 'foo' is a C11 feature
Non voglio il mio codice di dipendere da una caratteristica C11 e voglio essere sicuro che le funzioni nell'intestazione pubblica coincidano con l'implementazione. Come lo risolvo?
vedo un modo che è diviso in foo.h
foo.h
e foo_private.h
:
foo.h (guardie inclusione omesse per brevità):
struct foo_s;
#include "foo_private.h"
foo_private.h (guardie inclusione omesse per brevità) :
typedef struct foo_s foo;
foo* foo_create(void);
void foo_do_something(foo *foo);
e poi vorrei includere foo_private.h
in foo.c
e altri il codice includerebbe foo.h
.Ciò significherebbe che foo.c
non vede più la dichiarazione forward di foo_s
e quindi clang e iwyu dovrebbe essere felice. Significa anche che l'implementazione delle mie funzioni viene controllata per corrispondere all'intestazione.
Ma mentre questo funziona mi fa domando se questa è la soluzione migliore perché:
- sembra uno spreco avere un file di intestazione con solo due linee
- Non so di altri progetti che fare così (e guardando nel mio/usr/include non vedo nessuno dei due)
Quindi quale sarebbe una soluzione che soddisfi i tre criteri elencati in alto? O è la soluzione che ho trovato quella da seguire?
Non c'è bisogno di dichiarare '_foo_s struct;' 'dopo typedef struct _foo_s foo_t; '. Già solo quel typedef dichiara * sia * 'struct _foo_s' che' foo_t'. La seguente 'struct _foo_s;' non aggiunge nulla ad essa. È ridondante. Forse è esattamente quello che iwyu stava cercando di dirti. – AnT
Il codice che si sta visualizzando non dà luogo a un doppio 'typedef'. Non dovresti avere problemi se hai a che fare con protezioni che proteggono il contenuto del tuo file '.h'. –
OT: POSIX non consente tipi che terminano con '_t'. – alk