Comprendre les fichiers d'en-tête C : Types, utilisation et bonnes pratiques
Un fichier d'en-tête est un fichier avec l'extension .h qui contient des déclarations de fonctions C et des définitions de macros destinées à être partagées entre plusieurs fichiers sources. Il existe deux types de fichiers d'en-tête : ceux que le programmeur écrit lui-même et ceux fournis avec le compilateur.
Vous demandez l'utilisation d'un fichier d'en-tête dans votre programme en l'incluant avec la directive de préprocesseur C #include, comme vous l'avez vu avec l'inclusion du fichier d'en-tête stdio.h qui accompagne votre compilateur.
Inclure un fichier d'en-tête équivaut à copier son contenu, mais nous ne le faisons pas car cela serait source d'erreurs et ce n'est pas une bonne idée de copier le contenu d'un fichier d'en-tête dans les fichiers sources, surtout si le programme comporte plusieurs fichiers sources.
Une pratique courante en C ou C++ consiste à placer toutes les constantes, macros, variables globales système et prototypes de fonctions dans les fichiers d'en-tête, puis à inclure ce fichier d'en-tête partout où c'est nécessaire.
Syntaxe d'inclusion
Les fichiers d'en-tête utilisateur et système sont tous deux inclus à l'aide de la directive de préprocesseur #include. Elle a deux formes :
#include <fichier>
Cette forme est utilisée pour les fichiers d'en-tête système. Elle recherche un fichier nommé 'fichier' dans une liste standard de répertoires système. Vous pouvez ajouter des répertoires à cette liste avec l'option -I lors de la compilation.
#include "fichier"
Cette forme est utilisée pour les fichiers d'en-tête de votre propre programme. Elle recherche un fichier nommé 'fichier' dans le répertoire contenant le fichier courant. Vous pouvez également ajouter des répertoires à cette liste avec l'option -I lors de la compilation.
Fonctionnement de l'inclusion
La directive #include demande au préprocesseur C de scanner le fichier spécifié comme entrée avant de continuer avec le reste du fichier source courant. La sortie du préprocesseur contient la sortie déjà générée, suivie de la sortie résultant du fichier inclus, suivie de la sortie provenant du texte après la directive #include.
Par exemple, si vous avez un fichier d'en-tête en_tete.h comme suit :
char *test(void);
et un programme principal appelé programme.c qui utilise ce fichier d'en-tête :
int x;
#include "en_tete.h"
int main(void) {
puts(test());
}
le compilateur verra le même flux de jetons que si programme.c contenait :
int x;
char *test(void);
int main(void) {
puts(test());
}
En-têtes à inclusion unique
Si un fichier d'en-tête est inclus deux fois, le compilateur traitera son contenu deux fois, ce qui provoquera une erreur. La méthode standard pour l'éviter consiste à enfermer tout le contenu réel du fichier dans une conditionnelle :
#ifndef FICHIER_EN_TETE #define FICHIER_EN_TETE /* tout le contenu du fichier d'en-tête */ #endif
Cette construction est communément appelée un wrapper #ifndef. Lorsque l'en-tête est inclus à nouveau, la conditionnelle est fausse car FICHIER_EN_TETE est défini. Le préprocesseur saute alors tout le contenu du fichier, et le compilateur ne le voit pas deux fois.
Inclusions calculées
Il est parfois nécessaire de sélectionner l'un parmi plusieurs fichiers d'en-tête différents à inclure dans votre programme. Par exemple, ils pourraient spécifier des paramètres de configuration pour différents systèmes d'exploitation. Vous pourriez faire cela avec une série de conditionnelles :
#if SYSTEME_1 # include "systeme_1.h" #elif SYSTEME_2 # include "systeme_2.h" #elif SYSTEME_3 ... #endif
Mais cela devient fastidieux à mesure que cela grandit. Le préprocesseur offre alors la possibilité d'utiliser une macro pour le nom de l'en-tête. C'est ce qu'on appelle une inclusion calculée. Au lieu d'écrire un nom d'en-tête comme argument direct de #include, vous y mettez simplement un nom de macro :
#define SYSTEME_H "systeme_1.h" ... #include SYSTEME_H
SYSTEME_H sera étendu, et le préprocesseur recherchera systeme_1.h comme si le #include avait été écrit ainsi à l'origine. SYSTEME_H pourrait être défini par votre Makefile avec une option -D.
Langue C
- Gestion des fichiers en C : Maîtriser les E/S avec fopen, fprintf, fread et fseek
- Entrées/sorties de fichiers Python : maîtriser les opérations sur les fichiers
- Maîtriser les opérations sur les fichiers Java avec java.io – Création, lecture, écriture et suppression
- Comprendre les Fichiers STL : La Colonne Vertébrale de l'Impression 3D
- Maîtriser les entrées/sorties de fichiers en Verilog : Ouvrir, Lire, Écrire et Fermer
- Maîtriser les entrées/sorties fichiers en C : Création, ouverture et gestion
- Maîtriser les entrées/sorties fichier en C++ : Lecture et écriture avec fstream
- Maîtriser les entrées/sorties fichiers en C# : lecture, écriture et flux
- Entrées/Sorties de fichiers en Python : Maîtriser les opérations de lecture et d'écriture