Intestazione per file sorgente

Sto cercando di capire lo scopo dietro una intestazione per ogni metodo del file sorgente. A mio avviso, le intestazioni sono pensate per condividere dichiarazioni di funzioni, typedef e macro tra diversi file che li utilizzano. Quando crei un file di intestazione per il tuo file .c ha lo svantaggio che ogni volta che vuoi vedere una dichiarazione di funzione o una macro devi fare riferimento al file di intestazione, e generalmente è più semplice che tutto sia in un file sorgente (non l’intero software, ovviamente).

Quindi perché i programmatori usano questo metodo?

I file di intestazione in C dichiarazioni separate (che devono essere disponibili per ciascun file .c che utilizza le funzioni) dalle definizioni (che devono essere in un unico punto). Inoltre, forniscono un po ‘di modularità, dal momento che è ansible inserire solo l’interfaccia pubblica in un file di intestazione e non menzionare funzioni e variabili statiche che dovrebbero essere interne al file .c. Questo utilizza il file system per fornire un’interfaccia pubblica e un’implementazione privata.

La pratica di un file .h in un file .c è per lo più conveniente. In questo modo, sai che le dichiarazioni sono nel file .h e le definizioni nel file .c corrispondente.

L’organizzazione logica e strutturata e i file di piccole dimensioni consentono:

  • programmazione più veloce e migliore : suddividere il codice in blocchi più gestibili e comprensibili rende più facile trovare, comprendere e modificare il codice pertinente.
  • riutilizzabilità del codice : diversi “moduli” di codice possono essere separati in gruppi di file sorgente / header che è ansible integrare più facilmente in programmi diversi.
  • migliore “incapsulamento” : solo i file .c che includono specificamente quell’intestazione possono utilizzare le funzionalità da esso, il che aiuta a ridurre al minimo le relazioni tra le diverse parti del codice, il che facilita la modularità. Non ti impedisce di usare le cose da qualsiasi luogo, ma ti aiuta a pensare perché un particolare file c ha bisogno di accedere a funzioni dichiarate in una particolare intestazione.
  • Aids teamwork : due programmatori che provano a modificare contemporaneamente lo stesso file di codice causano problemi (ad esempio blocchi esclusivi) o lavori extra (ad es. Code merges) che si rallentano a vicenda.
  • compilazioni più veloci – se si dispone di un’intestazione, ogni volta che si effettua una modifica, è necessario ricompilare tutto. Con molte piccole intestazioni, solo i file .c che includono l’intestazione modificata devono essere ricostruiti.
  • manutenibilità e refactoring più semplici – per tutti i motivi sopra esposti

In particolare, “un’intestazione per ogni file sorgente” rende molto facile trovare le dichiarazioni rilevanti per il file c su cui si sta lavorando. Non appena si inizia a coalizzare più intestazioni in un singolo file, inizia a diventare difficile da mettere in relazione i file c e h, e in definitiva rende molto più difficile la creazione di un’applicazione di grandi dimensioni. Se lavori solo su una piccola applicazione, è comunque consigliabile prendere l’abitudine di utilizzare un approccio scalabile.

Perché, come hai detto tu stesso, non è fattibile mettere l’intero software in un unico file sorgente.

Se il tuo programma è molto piccolo, allora sì è più semplice mettere tutto in un file .c. Man mano che il programma diventa più grande, diventa utile organizzare le cose mettendo insieme le relative funzioni in diversi file .c. Inoltre, nei file .h puoi limitare le dichiarazioni che tu dai alle dichiarazioni di cose che dovrebbero essere usate da cose in altri file .c. Se un file .c non contiene nulla che dovrebbe essere accessibile al di fuori di se stesso, non ha bisogno di intestazione.

Per esempio, se .c ha la funzione foo () e fooHelper (), ma nessuno tranne foo () dovrebbe chiamare direttamente fooHelper (), quindi mettendo foo () e fooHelper () in foo.c, mettendo solo la dichiarazione di foo () in foo.h, e dichiarando fooHelper () come statico, aiuta a far rispettare le altre parti del tuo programma che dovrebbero solo accedere a foo () e non dovrebbero sapere o preoccuparsi di fooHelper (). Una specie di forma di incapsulamento non orientata agli oggetti.

Infine, i motori sono in genere abbastanza intelligenti da ribuild solo i file che sono stati modificati dall’ultima build, quindi la suddivisione in più file .c (utilizzando i file .h per condividere ciò che deve essere condiviso) aiuta a velocizzare le build.

Metti solo il file di intestazione il minimo indispensabile che gli altri file sorgente devono “vedere” per compilare. Ho visto alcune persone che mettono tutto il non-codice nel file di intestazione (tutti typedefs, tutti # define, tutte le strutture, ecc.) Anche se nient’altro nel codebase userà quelli. Ciò rende il file di intestazione molto più difficile da leggere per te e per coloro che desiderano utilizzare il modulo.

I programmatori utilizzano questo metodo perché consente loro di separare l’interfaccia dall’implementazione garantendo al tempo stesso che il codice client e l’implementazione concordino sulle dichiarazioni delle funzioni . Il file .h è il “single point of truth” (vedi Do not Repeat Yourself) sul prototipo di ciascuna funzione.

(Il codice client è il codice che #include il file .h per utilizzare le funzioni esportate, ma non implementa nessuna delle funzioni nel .h.)

Non hai bisogno di una intestazione per file sorgente. Un’intestazione per modulo, contenente l’interfaccia pubblica, e forse un’intestazione aggiuntiva contenente dichiarazioni private ecc condivisa tra i file in quel modulo.

Generalmente un’intestazione per un metodo di file sorgente significa che si dichiarano solo le funzioni da quell’unità di compilazione in quell’intestazione.

In questo modo non inquini con le dichiarazioni che non ti servono. (nel progetto di software di grandi dimensioni potrebbe essere un problema)

Per quanto riguarda le unità di compilazione separate, queste accelerano la compilazione e possono aiutarti a evitare le collisioni se i simboli privati ​​vengono dichiarati statici.