48 votes

Inclusion de fichiers d'en-tête dans C / C ++ plusieurs fois

Est-il toujours utile d'inclure un fichier d'en-tête plus d'une fois en C ou C++?

Si le mécanisme n'est jamais utilisé, pourquoi le compilateur jamais à vous préoccuper d'inclure un fichier deux fois; si c'était vraiment inutile, ne serait-il pas plus pratique si de nouveaux compilateurs fait en sorte que chaque en-tête est inclus qu'une seule fois?

Edit:

Je comprends qu'il existe des façons de faire les choses comme inclure des gardes et pragma une fois, mais pourquoi devriez-vous avoir à spécifier même? Ne devrait-elle pas être le comportement par défaut du compilateur d'inclure les fichiers qu'une seule fois?

30voto

Pubby Points 29386

Oui, c'est utile lors de la génération de code avec le préprocesseur, ou faire des trucs comme Boost.PP.

Pour un exemple, voir X Macros. L'idée de base est que le fichier contient le corps de la macro et de vous #define les arguments et puis, #include . Voici un exemple artificiel:

macro.xpp

std::cout << MESSAGE;
#undef MESSAGE

file.cpp:

int main() {
# define MESSAGE "hello world"
# include "macro.xpp"
}

Cela vous permet également d'utiliser #if et les amis sur les arguments, quelque chose de normal que les macros ne peuvent pas faire.

28voto

Jerry Coffin Points 237758

Oui, y compris un en-tête plus d'une fois peut être utile (même si c'est assez rare). L'exemple canonique est - <assert.h>, qui définit asssert différemment selon qu' NDEBUG est définie ou non. En tant que tel, il peut être judicieux de l'inclure, puis une (généralement conditionnelle) de la définition de NDEBUG, suivie de l'inclure à nouveau, avec (au moins potentiellement) définitions différentes de l' assert:

L' assert macro est redéfini en fonction de l'état actuel de l' NDEBUG chaque fois que <assert.h> est inclus1.

La plupart des en-têtes, cependant, aller pour certaines douleurs à être idempotent (c'est à dire, pour avoir les mêmes effets, peu importe combien de fois ils sont inclus).


1C99, §7.2/1.

14voto

Tony D Points 43962

Un exemple typique (non testé) - le fait qu’il factorise une liste d’énumérations afin qu’elles apparaissent systématiquement dans un enum et dans du code en continu:

 // states.h
X(Uninitialised)
X(Initialised)
X(Running)
X(Complete)
X(Shutdown)

// app.c++
#if defined(X)
# error X is already defined
#endif

enum States {
    #define X(TAG) TAG,
    #include "states.h"
    #undef X
    Extra_So_Trailing_Comma_Ignored
};

std::ostream& operator<<(std::ostream& os, const States& state)
{
    #define X(TAG) if (state == TAG) return os << #TAG;
    #include "states.h"
    #undef X
    return os << "<Invalid-State>";
}
 

4voto

Thomas Clemensen Points 2117

Oui, il serait plus pratique de ne l'inclure qu'une seule fois et c'est pourquoi vous utilisez #pragma une fois. en C ++ :)

Modifier:

Remarque: #pragma once n'est pas portable. Vous pouvez utiliser

 #ifndef FILENAME_H
#define FILENAME_H
 

en haut de vos fichiers d'en-tête à la place si vous voulez que ce soit portable.

1voto

Dimitris Staikos Points 116

L'inclusion multiple peut être utilisée chaque fois que vous avez besoin d'une génération de code "ennuyeuse" que vous ne voulez pas gérer manuellement, encore et encore.

L'exemple classique serait une énumération C / C ++ et les chaînes correspondantes, qui ressemblent plus ou moins à ceci:

 // MYENUM_VALUES.H
MYENUMVALUE(a)
MYENUMVALUE(b)
MYENUMVALUE(c)
MYENUMVALUE(d)

// MYENUM.H
#define MYENUMVALUE(x) x,
enum MyEnum
{
#include "MYENUM_VALUES.H"
}
#undef MYENUMVALUE

// MYENUMTOSTRING.C
#define MYENUMVALUE(x) case x : return #x;

const char * MyEnumToString(MyEnum val)
{
    switch (val)
    {
    #include "MYENUM_VALUES.H"
    default return "unknown";
    }
} 
#undef MYENUMVALUE
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X