Pourquoi #ifndef et #define sont-ils utilisés dans les fichiers d'en-tête C ++?

496

J'ai vu du code comme celui-ci généralement au début des fichiers d'en-tête:

#ifndef HEADERFILE_H
#define HEADERFILE_H

Et à la fin du fichier se trouve

#endif

Quel en est le but?

Asad Khan
la source
36
+1 - Moi aussi, j'avais le même doute, et j'ai obtenu beaucoup plus de bonnes réponses ici, peut être utile pour les futurs visiteurs: stackoverflow.com/q/3246803/1134940
Abid Rahman K
6
Je veux ajouter à cela que vous pouvez également utiliser #pragma une fois , c'est tout ce que vous avez à faire et cela sert le même but que ifndef. Pour une comparaison des deux, voir: stackoverflow.com/questions/1143936/…
Dimension
3
Mieux #pragmavaut mentionner ce qu'est un : il active une fonctionnalité spécifique au compilateur. Bien qu'il #pragma oncesoit très largement pris en charge, il n'est pas standard.
Potatoswatter
3
@Dimension: la propre documentation de GNU ( info cppou regardez ici ) dit "elle n'est pas reconnue par tous les préprocesseurs, vous ne pouvez donc pas vous y fier dans un programme portable.". Et GNU cpp optimise l' #ifndefidiome commun et portable pour qu'il soit aussi efficace que #pragma once.
Keith Thompson
3
Quelques points à considérer: N'utilisez pas un nom de macro commençant par un trait de soulignement; ces identifiants sont réservés à l'implémentation. Plus subtilement, #ifndef HEADERFILE_Hpeut violer l'espace de noms de l'implémentation du nom de l'en-tête qui commence par E; les identifiants commençant par Eet un chiffre ou une lettre majuscule sont réservés à <errno.h>. Je suggère #ifndef H_HEADERFILE.
Keith Thompson

Réponses:

527

Ceux-ci sont appelés #include gardes .

Une fois l'en-tête inclus, il vérifie si une valeur unique (dans ce cas HEADERFILE_H) est définie. Ensuite, s'il n'est pas défini, il le définit et continue vers le reste de la page.

Lorsque le code est à nouveau inclus, le premier ifndeféchoue, ce qui entraîne un fichier vide.

Cela empêche la double déclaration des identifiants tels que les types, les énumérations et les variables statiques.

LiraNuna
la source
1
Koning Baard XIV: VC a même un #pragma oncequi fait la même chose :-)
Joey
95
De plus, cela empêche les inclusions récursives ... Imaginez que "alice.h" inclut "bob.h" et "bob.h" inclut "alice.h" et qu'ils n'ont pas de gardes inclus ...
Kevin Dungs
@Kevin: c'est ce que je veux dire. Je voulais manipuler un formulaire qui a été ouvert par le formulaire à manipuler. Cela a donné beaucoup d'erreurs et je ne savais pas quoi faire. J'ai abandonné =)
6
@ Јοеу: #pragma oncen'est pas portable; l' #ifndefidiome commun est recommandé.
Keith Thompson
2
@CIsForCookies Insérez "une règle de définition" dans votre moteur de recherche préféré.
David Schwartz
33
#ifndef <token>
/* code */
#else
/* code to include if the token is defined */
#endif

#ifndefvérifie si le jeton donné a été #definedplus tôt dans le fichier ou dans un fichier inclus; sinon, il inclut le code entre celui-ci et la clôture #elseou, si aucun #elsen'est présent, l' #endifinstruction. #ifndefest souvent utilisé pour rendre les fichiers d'en-tête idempotents en définissant un jeton une fois que le fichier a été inclus et en vérifiant que le jeton n'a pas été défini en haut de ce fichier.

#ifndef _INCL_GUARD
#define _INCL_GUARD
#endif
Roy
la source
4
Les identifiants commençant par un trait de soulignement sont réservés; vous ne devez pas les définir vous-même. Utilisez quelque chose comme #ifndef H_HEADER_NAME.
Keith Thompson
5
Je sais que c'est un vieux commentaire, mais en fait, la restriction de soulignement ne s'applique qu'aux "identificateurs externes" - les identificateurs qui pourraient se retrouver dans la table des symboles de l'objet compilé, c'est-à-dire les variables globales et les noms de fonction. Elle ne s'applique pas aux noms de macro.
Stu
1
Le commentaire de Stu est-il vrai? Je viens de lire stackoverflow.com/questions/228783/… et maintenant je n'en suis pas si sûr.
Will
10

Cela empêche l'inclusion multiple du même fichier d'en-tête plusieurs fois.

#ifndef __COMMON_H__
#define __COMMON_H__
//header file content
#endif

Supposons que vous ayez inclus ce fichier d'en-tête dans plusieurs fichiers. Donc, la première fois que __COMMON_H__ n'est pas défini, il sera défini et le fichier d'en-tête sera inclus.

La prochaine fois que __COMMON_H__ est défini, il ne sera donc plus inclus.

Sandeep_black
la source
1

Ils sont appelés ifdef ou incluent des gardes.

Si vous écrivez un petit programme, il peut sembler que ce n'est pas nécessaire, mais au fur et à mesure que le projet se développe, vous pouvez inclure plusieurs fois intentionnellement ou non un fichier, ce qui peut entraîner un avertissement de compilation comme une variable déjà déclarée.

#ifndef checks whether HEADERFILE_H is not declared.
#define will declare HEADERFILE_H once #ifndef generates true.
#endif is to know the scope of #ifndef i.e end of #ifndef

S'il n'est pas déclaré, ce qui signifie que #ifndef génère vrai, alors seule la partie entre #ifndef et #endif est exécutée sinon. Cela évitera de déclarer à nouveau les identifiants, énumérations, structure, etc ...

Mohit Jain
la source