Article de reference

inclure la garde

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'évit...

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 »

struct Foo { int membre ; };

Fichier « Parent.h »

#include "Grandparent.h"

Fichier « Enfant.c »

#include "Grandparent.h" #include "Parent.h"

Résultat

// De "Grandparent.h" struct Foo { int member ; }; // De "Parent.h" struct Foo { int member ; };

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 »

#ifndef GRANDPARENT_H #define GRANDPARENT_Hstruct Foo { int membre ; };#endif // GRAND-PARENT_H

Fichier « Parent.h »

#include "Grandparent.h"

Fichier « Enfant.c »

#include "Grandparent.h" #include "Parent.h"

Étape intermédiaire

// Contenu de « Grandparent.h » #ifndef GRANDPARENT_H // GRANDPARENT_H n'a pas été défini #define GRANDPARENT_H// Cette définition a été collée struct Foo { int membre ; };#endif // GRAND-PARENT_H// Contenu de « Parent.h » #ifndef GRANDPARENT_H // GRANDPARENT_H était déjà défini #define GRANDPARENT_H// Cette définition n'a pas été collée struct Foo { int membre ; };#endif // GRAND-PARENT_H

Résultat

struct Foo { int membre ; };

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 une XPROCEDUREinstruction, similaire à une PROCEDUREautre, qui ignore la deuxième occurrence et les suivantes d'un élément XPROCEDUREportant le même nom.)
  • Directive d' Objective-C#import (voir ci-dessus)
  • PHP 's include_once

Plus d articles de Worldlex Wiki

Revenez a l index pour explorer davantage de pages sur l histoire, la science, la culture, la geographie et la societe en francais.

Explorer l index