HOWTO · C

#ifndef Inclure les gardes dans C

Cet article présente la manière d'utiliser l'ifndef pour inclure les gardes dans les C

Sur cette page

Cet article démontrera les multiples méthodes d’utilisation de la #ifndef, y compris les gardes en C.

Utiliser ifndef pour protéger contre l’inclusion multiple de fichiers d’en-tête dans le langage C

Les fichiers d’en-tête en C sont utilisés pour définir l’interface des fonctions implémentées dans le fichier source du même nom. L’interface comprend généralement des prototypes de fonctions, des définitions de structures de données accessibles au public, et quelques autres éléments divers.

Notez que les fichiers d’en-tête peuvent être inclus dans le fichier source plusieurs fois, ce qui entraîne des erreurs de compilation. Habituellement, cela est évité grâce à la directive de préprocesseur #ifndef, qui est appelée wrapper #ifndef. Lorsque le contenu du fichier d’en-tête est inclus dans la structure montrée dans l’exemple suivant, où la directive #ifndef MY_GUARD est le point de départ et #endif la fin. La directive ifndef vérifie si la macro MY_GUARD est définie, sinon elle continue et la définit avec la directive suivante. Dans le cas où l’utilisateur inclut le même en-tête pour la seconde fois, la directive ifndef évaluera false et ignorera le code avant la directive #endif. En conséquence, le compilateur n’obtiendra qu’une seule copie du code de ce fichier d’en-tête et le traduira avec succès.

#include <stdio.h>

#ifndef MY_GUARD
#define MY_GUARD 1

#define PER(D) #D
#define JOIN(A, B) (A##B)
#define JOINX(A, B) JOIN(A, B)

int power(int base, int n) {
  int p = base;
  for (size_t i = 0; i < n; i++) {
    p *= base;
  }
  return p;
}
#endif

Une autre méthode pour obtenir les mêmes résultats est d’inclure la directive #pragma once dans le fichier d’en-tête. Le préprocesseur n’analyse ces fichiers d’en-tête qu’une seule fois et garantit qu’ils ne seront pas lus à nouveau. L’un des inconvénients de la méthode suivante est qu’elle présente une faible portabilité entre les différents préprocesseurs, et il est donc préférable de conserver la méthode wrapper #ifndef pour assurer une meilleure flexibilité de la base de code.

#include <stdio.h>

#pragma once

#define PER(D) #D
#define JOIN(A, B) (A##B)
#define JOINX(A, B) JOIN(A, B)

int power(int base, int n) {
  int p = base;
  for (size_t i = 0; i < n; i++) {
    p *= base;
  }
  return p;
}

Utiliser la directive ifndef pour s’assurer que les macros ne sont pas définies plusieurs fois dans C

On peut aussi utiliser la directive ifndef pour vérifier si l’expression macro donnée a déjà été définie. La logique fonctionne exactement comme dans l’exemple précédent ; si l’expression n’est pas définie, la directive # define suivante est traitée en conséquence. La seule ligne entre la directive #ifndef et la directive #endif est une définition de macro, ce qui signifie que si la condition est fausse, seule la définition de la macro donnée est ignorée.

#include <stdio.h>
#include <stdlib.h>

#define PER(D) #D

#ifndef DLEVEL
#define DLEVEL 6
#endif

int main() {
  for (int j = 0; j < DLEVEL; ++j) {
    printf("%s\n", PER(stringify this));
  }

  exit(EXIT_SUCCESS);
}