Schema Generale di un File Header in Linguaggio C
Nelle lezioni precedenti abbiamo affrontato lo studio di diversi aspetti dei file header in linguaggio C:
- Ne abbiamo studiato lo scopo e l'utilizzo attraverso l'uso della direttiva
#include
; - Ne abbiamo visto l'impiego per condividere tipi, costanti, variabili globali e funzioni tra più file sorgenti;
- Abbiamo studiato l'impiego dell'inclusione innestata e abbiamo affrontato il problema dell'inclusione multipla.
In base a queste conoscenze vedremo, adesso, uno schema generale di un file header in linguaggio C che può essere adoperato nella maggior parte dei casi.
Struttura generale di un file header
Quando si vuole creare un file header in linguaggio C, è importante seguire una struttura ben definita per facilitarne la lettura e la manutenzione.
Possiamo dividere un file header in diverse parti, ognuna delle quali contiene un tipo specifico di dichiarazioni:
-
Guardie di inclusione: sono delle direttive di preprocessore che servono a evitare l'inclusione multipla dello stesso file header.
Queste direttive sono composte da un blocco di codice che definisce una macro e due direttive
#ifndef
e#define
che controllano se la macro è già stata definita. Se la macro non è stata definita, il blocco di codice viene eseguito e la macro viene definita. Se la macro è già stata definita, il blocco di codice non viene eseguito. Infine, alla fine del file header, viene definita la macro con la direttiva#endif
.#ifndef NOME_FILE_H #define NOME_FILE_H /* Dichiarazioni */ #endif
-
Inclusioni: sono le direttive di preprocessore che includono le librerie necessarie per il file header.
Un file header potrebbe, a sua volta, avere necessità di includere altri file header o librerie di sistema. Queste inclusioni vanno sempre prima delle altre dichiarazioni.
#include <file_di_sistema_1.h> #include <file_di_sistema_2.h> #include "file_locale_1.h" #include "file_locale_2.h"
-
Dichiarazioni di costanti: sono le dichiarazioni di costanti, come le costanti numeriche e le costanti di stringa.
Le costanti vengono definite con la direttiva
#define
e vengono utilizzate per definire valori che non cambiano durante l'esecuzione del programma.#define COSTANTE_1 10 #define COSTANTE_2 "costante"
-
Dichiarazioni di tipi: sono le dichiarazioni di tipi personalizzati, come le strutture, le enumerazioni e i tipi definiti dall'utente.
Queste dichiarazioni vengono utilizzate per definire nuovi tipi di dati che possono essere utilizzati in tutto il programma.
typedef struct { int campo_1; char campo_2; } TipoStruttura; typedef enum { Valore_1, Valore_2, Valore_3 } TipoEnumerazione;
-
Dichiarazioni di variabili: sono le dichiarazioni di variabili globali.
Le variabili globali vengono dichiarate con la parola chiave
extern
per indicare che sono definite in un altro file sorgente.extern int variabile_globale_1; extern char variabile_globale_2;
-
Dichiarazioni di funzioni: sono le dichiarazioni di funzioni.
Le funzioni vengono dichiarate con il loro prototipo, cioè con il loro nome, i tipi dei parametri e il tipo di ritorno.
void funzione_1(int argomento_1, char argomento_2); void funzione_2(int argomento_1, char argomento_2);
Ovviamente, tutte queste parti sono opzionali. Per quanto riguarda, però, le guardie di inclusione, è sempre consigliabile includerle per evitare l'inclusione multipla del file header.
Di seguito è riportato uno schema generale di un file header in linguaggio C:
/* Parte 1: Guardie di Inclusione */
#ifndef NOME_FILE_H
#define NOME_FILE_H
/* Parte 2: Inclusioni */
#include <file_di_sistema_1.h>
#include <file_di_sistema_2.h>
#include "file_locale_1.h"
#include "file_locale_2.h"
/* Parte 3: Dichiarazioni di Tipi */
typedef struct {
int campo_1;
char campo_2;
} TipoStruttura;
typedef enum {
Valore_1,
Valore_2,
Valore_3
} TipoEnumerazione;
/* Parte 4: Dichiarazioni di Costanti */
#define COSTANTE_1 10
#define COSTANTE_2 "costante"
/* Parte 5: Dichiarazioni di Variabili */
extern int variabile_globale_1;
extern char variabile_globale_2;
/* Parte 6: Dichiarazioni di Funzioni */
void funzione_1(int argomento_1, char argomento_2);
void funzione_2(int argomento_1, char argomento_2);
/* Parte 7: Fine Guardie di Inclusione */
#endif
Questo schema di file header va bene nella maggior parte dei casi, ma può variare a seconda delle esigenze del progetto. Ad esempio, se il file header è molto grande, potrebbe essere utile suddividerlo in più file header per facilitarne la manutenzione.