Cosa dovrebbe e cosa non dovrebbe essere in un file di intestazione? [chiuso]

57

Quali cose non dovrebbero assolutamente mai essere incluse in un file di intestazione?

Se per esempio sto lavorando con un formato standard del settore documentato che ha molte costanti, è una buona pratica definirle in un file di intestazione (se sto scrivendo un parser per quel formato)?

Quali funzioni dovrebbero andare nel file di intestazione?
Quali funzioni non dovrebbero?

    
posta Moshe Magnes 06.10.2012 - 10:13
fonte

5 risposte

46

Che cosa inserire nelle intestazioni:

  • Il set minimo di #include di direttive necessarie per rendere l'intestazione compilabile quando l'intestazione è inclusa in qualche file sorgente.
  • Definizioni dei simboli preprocessore di cose che devono essere condivise e che possono essere eseguite solo tramite il preprocessore. Anche in C, i simboli del preprocessore sono mantenuti al minimo.
  • Inoltra dichiarazioni di strutture necessarie per rendere compilabili le definizioni della struttura, i prototipi di funzione e le dichiarazioni delle variabili globali nel corpo dell'intestazione.
  • Definizioni di strutture dati ed enumerazioni condivise tra più file sorgente.
  • Dichiarazioni per funzioni e variabili le cui definizioni saranno visibili al linker.
  • Definizioni di funzioni integrate, ma fai attenzione qui.

Ciò che non appartiene a un'intestazione:

  • Direttive #include gratuite. Quelli gratuiti comprendono la ricompilazione di cose che non hanno bisogno di essere ricompilate, e possono a volte renderlo tale che un sistema non possa essere compilato. Non #include un file in un'intestazione se l'intestazione non ha bisogno di quell'altro file di intestazione.
  • Simboli di preprocessore il cui intento potrebbe essere ottenuto da qualche meccanismo, qualsiasi meccanismo, diverso dal preprocessore.
  • Molte e molte definizioni di struttura. Dividili in intestazioni separate.
  • Definizioni incorporate di funzioni che richiedono un #include aggiuntivo, che sono soggette a modifiche o che sono troppo grandi. Quelle funzioni inline dovrebbero avere pochi fan o fan, e se hanno fan out, dovrebbero essere localizzate in robe definite nell'header.

Che cosa costituisce l'insieme minimo di dichiarazioni #include ?

Questa risulta essere una domanda non banale. Definizione TL; DR: un file di intestazione deve includere i file di intestazione che definiscono direttamente ciascuno dei tipi direttamente utilizzati o che dichiarano direttamente ciascuna delle funzioni utilizzate nel file di intestazione in questione, ma non devono includere nient'altro. Un puntatore o un tipo di riferimento C ++ non si qualifica come uso diretto; i riferimenti avanzati sono preferiti.

C'è un posto per una direttiva #include gratuita, e questo è in un test automatico. Per ogni file di intestazione in un pacchetto software, viene generato automaticamente e quindi viene compilato quanto segue:

#include "path/to/random/header_under_test"
int main () { return 0; }

La compilazione dovrebbe essere pulita (cioè, priva di avvisi o errori). Avvertimenti o errori relativi a tipi incomplete o tipi sconosciuti indicano che il file di intestazione in prova ha alcune direttive #include mancanti e / o dichiarazioni forward mancanti. Nota bene: solo perché il test passa non significa che l'insieme delle direttive #include sia sufficiente, figuriamoci minimo.

    
risposta data 06.10.2012 - 16:39
fonte
13

Oltre a ciò che è già stato detto.

I file H dovrebbero sempre contenere:

  • Documentazione del codice sorgente !!! Al minimo, qual è lo scopo dei vari parametri e i valori restituiti delle funzioni.
  • Guardie di intestazione, #ifndef MYHEADER_H #define MYHEADER_H ... #endif

I file H non dovrebbero mai contenere:

  • Qualsiasi forma di allocazione dei dati.
  • Definizioni di funzioni. In alcuni casi le funzioni inline possono essere una rara eccezione.
  • Qualunque cosa etichettata static .
  • Typedef, #definiti o costanti che non hanno rilevanza con il resto dell'applicazione.

(Direi anche che non c'è mai alcun motivo per usare variabili globali / esterne non costanti, ovunque, ma questa è una discussione per un altro post.)

    
risposta data 08.10.2012 - 15:08
fonte
4

Probabilmente non dirò mai mai, ma le istruzioni che generano dati e codice mentre vengono analizzate non dovrebbero essere in un file .h.

Macro, funzioni e modelli in linea possono sembrare dati o codice, ma non generano codice mentre vengono analizzati, ma invece quando vengono utilizzati. Questi elementi spesso devono essere utilizzati in più di un file .c o .cpp, quindi appartengono alla .h.

A mio avviso, un file di intestazione dovrebbe avere l'interfaccia pratica minima per un corrispondente .c o .cpp. L'interfaccia può includere #definiti, classi, typedef, definizioni struct, prototipi di funzioni e definizioni esterne meno preferite per variabili globali. Tuttavia, se una dichiarazione viene utilizzata in un solo file sorgente, probabilmente dovrebbe essere esclusa da .h e essere contenuta nel file sorgente.

Alcuni potrebbero non essere d'accordo, ma i miei criteri personali per i file .h sono che includono tutti gli altri file .h che devono essere in grado di compilare. In alcuni casi, questo può essere un sacco di file, quindi abbiamo alcuni metodi efficaci per ridurre le dipendenze esterne come le dichiarazioni in avanti alle classi che ci permettono di usare i puntatori agli oggetti di una classe senza includere quello che potrebbe essere un grande albero di file include. / p>     

risposta data 06.10.2012 - 22:14
fonte
3

Il file di intestazione dovrebbe avere la seguente organizzazione:

  • tipo e definizioni costanti
  • dichiarazioni di oggetti esterni
  • dichiarazioni di funzioni esterne

I file di intestazione non dovrebbero mai contenere definizioni di oggetti, solo definizioni di tipi e dichiarazioni di oggetti.

    
risposta data 06.10.2012 - 11:40
fonte
0

Le istruzioni che generano dati e codice mentre vengono analizzati, non dovrebbero essere in un file .h . Per quanto riguarda il mio punto di vista, un file di intestazione dovrebbe avere solo l'interfaccia pratica minima per un corrispondente .c o .cpp .

    
risposta data 01.03.2014 - 17:08
fonte

Leggi altre domande sui tag