Dans les langages de programmation C et C++ , une protection #include , parfois appelée protection de macro , protection d'en-tête ou protection de fichier , est un moyen d'éviter le problème de la double inclusion lors de l'utilisation de la directive include .
Le préprocesseur C traite les directives d'inclusion comme celle d'inclure textuellement Foo.h et transclut le code de ce fichier dans une copie du fichier principal souvent appelée unité de traduction .#include"Foo.h"
Cependant, si une #includedirective relative à un fichier donné apparaît plusieurs fois lors de la compilation, le code sera dupliqué dans ce fichier. Si le fichier inclus contient une définition, cela peut provoquer une erreur de compilation en raison de la règle de définition unique , qui stipule que les définitions (telles que la définition d'une classe) ne peuvent pas être dupliquées dans une unité de traduction. #includeLes gardes empêchent cela en définissant une macro de préprocesseur lors de la première inclusion d'un fichier d'en-tête. Si ce fichier d'en-tête est inclus une seconde fois, la #includegarde empêchera la compilation du code qu'il contient.
Une alternative aux #includegardes est `#pragma once` . Cette directive non standard, mais couramment prise en charge par les compilateurs C et C++ , a le même objectif qu'une #includegarde, mais nécessite moins de code et ne requiert pas la définition d'une variable.
Les modules , introduits dans C++20 , éliminent la nécessité des #includegardes, car ils ne sont pas gérés par le préprocesseur. Les modules ne peuvent être importés qu'une seule fois dans une unité de traduction .
Double inclusion
Exemple
Le code C suivant illustre un problème réel qui peut survenir en l' #includeabsence de gardes :
Fichier « Grandparent.h »
Fichier « Parent.h »
Fichier « Enfant.c »
Résultat
Ici, le fichier Child.c inclut indirectement deux copies du texte du fichier d'en-tête Grandparent.h . Cela provoque une erreur de compilation , car le type de structure est ainsi défini deux fois. En C++, on parlerait de violation de la règle de définition unique .Foo
Utilisation des gardes #include
Exemple
Le même code que dans la section précédente est utilisé, avec l'ajout de #includegardes. Le préprocesseur C prétraite les fichiers d'en-tête, y compris les fichiers `<script>`, puis les prétraite récursivement . On obtient ainsi un fichier source fonctionnel.
Fichier « Grandparent.h »
Fichier « Parent.h »
Fichier « Enfant.c »
Étape intermédiaire
Résultat
Ici, la première inclusion de « Grandparent.h » définit la macro . Lorsque « Child.c » inclut « Grandparent.h » une seconde fois (tout en incluant « Parent.h »), le test renvoyant la valeur « faux », le préprocesseur passe directement à l'instruction `include` , évitant ainsi la seconde définition de la macro . Le programme compile alors correctement.GRANDPARENT_H#ifndef#endifstruct Foo
Discussion
Les conventions de nommage de la macro de garde peuvent varier d'un programmeur à l'autre . Parmi les autres formes courantes de l'exemple ci-dessus GRANDPARENT_INCLUDED, on trouve CREATORSNAME_YYYYMMDD_HHMMSS(avec les informations temporelles appropriées) et les noms générés à partir d'un UUID . (Toutefois, les noms commençant par un trait de soulignement et une majuscule (C et C++) ou tout nom contenant deux traits de soulignement (C++ uniquement), tels que _GRANDPARENT_Het GRANDPARENT__H, sont réservés à l'implémentation du langage et ne doivent pas être utilisés par l'utilisateur. )
Bien entendu, il est important d'éviter de dupliquer le même nom de macro include-guard dans différents fichiers d'en-tête, car l'inclusion du premier empêchera l'inclusion du second, entraînant la perte de toutes les déclarations, définitions en ligne ou autres #includeéléments présents dans le second fichier d'en-tête.
Problèmes
Pour que #includeles gardes fonctionnent correctement, chaque garde doit tester et définir conditionnellement une macro de préprocesseur différente. Par conséquent, un projet utilisant #includedes gardes doit définir une convention de nommage cohérente pour ses gardes d'inclusion et s'assurer que cette convention n'entre pas en conflit avec celle des en-têtes tiers utilisés, ni avec les noms des macros globales.
Pour cette raison, la plupart des implémentations C et C++ fournissent une directive non standard #pragma once. Cette directive, insérée en haut d'un fichier d'en-tête, garantit que le fichier n'est inclus qu'une seule fois. Le langage Objective-C (qui est un sur-ensemble du C) possède une #importdirective qui fonctionne exactement de la même manière #include, à la différence qu'elle inclut chaque fichier une seule fois, évitant ainsi le besoin de #includegardes.
Autres langues
Certains langages permettent de spécifier que le code ne doit être inclus qu'une seule fois, dans le fichier incluant, plutôt que dans le fichier inclus (comme avec les gardes d'inclusion C/C++ #pragma once) :
- PL/I utilise cette
%INCLUDEinstruction comme équivalent de la#includedirective C. IBM Enterprise PL/I prend également en charge l'%XINCLUDEinstruction qui « incorpore du texte externe dans le programme source s'il n'a pas été inclus précédemment ». (Il propose également uneXPROCEDUREinstruction, similaire à unePROCEDUREautre, qui ignore la deuxième occurrence et les suivantes d'un élémentXPROCEDUREportant le même nom.) - Directive d' Objective-C
#import(voir ci-dessus) - PHP 's
include_once