50 votes

Pourquoi le "#pragma once" de C / C ++ n'est-il pas une norme ISO?

Je suis actuellement en train de travailler sur un gros projet et le maintien de tous ceux qui comprennent les gardes me rend fou! De l'écriture à la main est frustrant perte de temps. Bien que de nombreux éditeurs peuvent générer comprenant des protections ce n'aide pas beaucoup:

  1. L'éditeur génère de la garde symbole basé sur un nom de fichier. Le problème se produit lorsque vous avez les en-têtes avec le même nom de fichier dans les répertoires différents. Deux d'entre eux d'obtenir le même inclure de la garde. Y compris la structure de répertoire dans la garde symbole aurait besoin d'un peu de fantaisie approche à partir de l'éditeur, depuis des barres obliques et les barres obliques inverses dans la macro ne sont pas la meilleure chose.

  2. Quand je dois renommer un fichier que je devrais renommer tous les inclure gardes ainsi (dans le ifndef, de définir et idéalement endif du commentaire). Ennuyeux.

  3. Préprocesseur est inondé avec des tonnes de symboles, sans la moindre idée de ce qu'ils signifient.

  4. Néanmoins, la définition est inclus une fois, compilateur encore ouvre-tête à chaque fois qu'il se réunit en-tête de l'inclusion.

  5. Inclure les gardes ne rentre pas dans les espaces de noms, ni de modèles. En fait, ils sont à subvertir les espaces de noms!

  6. Vous avez une chance que votre garde symbole ne sera pas unique.

Peut-être qu'ils ont été solution acceptable dans les moments où les programmes contenaient moins de 1000 en-têtes d'un seul répertoire. Mais de nos jours? Elle est ancienne, elle n'a rien à voir avec moderne des habitudes de codage. Ce qui me dérange le plus, c'est que cette question pourrait être presque compeletly résolu par la directive #pragma une fois. Pourquoi n'est-il pas une norme?

50voto

Charles Bailey Points 244082

Une directive comme #pragma once n'est pas négligeable pour définir dans un portable de façon claire, sans ambiguïté avantages. Certains des concepts pour lesquels il soulève des questions ne sont pas bien définis sur tous les systèmes qui prennent en charge C, et de le définir d'une manière simple peut fournir aucun avantage plus classiques comprennent gardes.

Lors de la compilation rencontres, #pragma once, comment faut-il identifier ce fichier de sorte qu'il ne comprend pas son contenu nouveau?

La réponse évidente est l'unique emplacement du fichier sur le système. C'est bien si le système a des endroits uniques pour tous les fichiers, mais de nombreux systèmes de fournir des liens (les liens symboliques et les liens) qui signifie qu'un 'fichier' ne dispose pas d'un emplacement unique. Si le fichier est de nouveau inclus juste parce qu'il a été trouvé par un nom différent? Probablement pas.

Mais maintenant, il y a un problème, comment est-il possible de définir le comportement de l' #pragma once d'une manière qui ait un sens exact sur toutes les plateformes, même ceux qui n'ont même pas de répertoires, sans parler des liens symboliques - et encore obtenir les comportements souhaités sur les systèmes qui en ont?

Vous pourriez dire qu'un des fichiers de l'identité est déterminée par son contenu, de sorte que si un fichier a un #pragma once et un fichier est inclus, qui a exactement le même contenu, puis la deuxième et ultérieures #includes n'ont pas d'effet.

C'est facile à définir et a bien défini la sémantique. Il a également de bonnes propriétés de telle sorte que si un projet est passé d'un système qui prend en charge et utilise le système de fichiers liens pour celui qui n'est pas le cas, il se comporte encore la même.

Sur le revers de la médaille, à chaque fois qu'un fichier à inclure est rencontré contenant un #pragma once de son contenu doit être vérifié par rapport à tous les autres fichier à l'aide d' #pragma once qui a déjà été inclus à ce jour. Ce qui implique un gain de performance similaire à l'utilisation d' #include gardes en tout cas, et ajoute un point non négligeable fardeau pour les rédacteurs du compilateur. De toute évidence, les résultats de ce qui pourrait être mis en cache, mais la même chose est vraie pour les classiques comprennent gardes.

Classiques comprennent les gardes de forcer le programmeur de choisir une macro qui est l'identificateur unique d'un fichier include, mais au moins, le comportement est bien définie et est simple à mettre en œuvre.

Étant donné les écueils potentiels et les coûts, et le fait que le conventionnel comprenant des protections pour faire le travail, il n'est pas surprenant pour moi que le comité de normalisation n'a pas senti la nécessité de normaliser #pragma once.

19voto

Michael Burr Points 181287

Inclure les gardes sont certainement une gêne, et C doit avoir été à l'origine conçue tels que les en-têtes de serait inclus par défaut - qui exigent une certaine option spéciale pour inclure un en-tête à plusieurs reprises.

Cependant, il n'était pas ,et vous êtes généralement tenus d'avoir à utiliser sont les gardiens. Cela dit, #pragma once est très largement prise en charge de sorte que vous pourriez être en mesure de s'en tirer avec de l'utiliser.

Personnellement, je résoudre votre 1er problème (même nom inclure des fichiers) par l'ajout d'un GUID à inclure les garde. C'est moche, et la plupart des gens le déteste (je suis souvent contraint de ne pas l'utiliser au travail), mais votre expérience montre que l'idée a une certaine valeur, même si c'est affreusement laid (mais encore une fois, l'ensemble de l'inclure la garde de la chose est une sorte de hack - pourquoi ne pas aller au bout?):

#ifndef C_ASSERT_H_3803b949_b422_4377_8713_ce606f29d546
#define C_ASSERT_H_3803b949_b422_4377_8713_ce606f29d546

// blah blah blah...

#endif

J'ai entendu dire que les compilateurs ne fait pas de rouvrir les fichiers d'en-tête qui ont des gardes (qu'ils ont appris à reconnaître l'idiome). Je ne suis pas sûr si cela est vrai (ou dans quelle mesure il est vrai), je n'ai jamais mesuré. J'ai aussi ne vous inquiétez pas à ce sujet, mais mes projets ne sont pas si énorme que c'est un problème.

Mon GUID hack assez bien résout les articles 1, 5, et 6. Je viens de vivre avec des articles 2, 3 et 4. En fait, pour le point 2, vous pourriez vivre sans renommer les inclure garde macro lorsque vous renommez le fichier en tant que le GUID permettra de s'assurer qu'elle reste unique. En fait, il n'y a pas de raison d'intégrer le nom du fichier à voir avec le GUID. Mais je n' - tradition, je suppose.

14voto

jmucchiello Points 10521
  1. Combien de fois avez-vous à ajouter un fichier include pour ce projet? Est-il vraiment si difficile d'ajouter DIRNAME_FILENAME à la garde? Et il y a toujours Guid.
  2. Avez-vous vraiment renommer les fichiers que souvent? Jamais? En outre, en mettant la GARDE dans la #endif est tout aussi ennuyeux que tout autre commentaire inutile.
  3. Je doute que votre 1000 fichiers d'en-tête de la garde définit même un petit pourcentage du nombre d'définit générés par les bibliothèques de votre système (en particulier sur Windows).
  4. Je pense que MSC 10 pour DOS (20 ans) a gardé la trace de ce que les en-têtes ont été inclus et si elles contenaient des gardes ignorez si inclus de nouveau. C'est l'ancienne technologie.
  5. les espaces de noms et les modèles ne couvrent pas les en-têtes. Chère moi-même, ne me dites pas que vous faites cela:

    template <typename foo>
    class bar {
    #include "bar_impl.h"
    };
    
  6. Vous avez dit que déjà.

9voto

Xentrax Points 191

Comme on l'a déjà noté, C++ Standard doit tenir compte des différentes plates-formes de développement dont certains peuvent avoir des limitations de prise de #pragma once de soutien impossible à mettre en œuvre.

D'autre part, le support pour les threads n'a pas été ajoutée pour la même raison que précédemment, mais plus récente Norme C++ comprend threads néanmoins. Et dans ce dernier cas, on peut le cross-compiler pour un nombre très restreint de la plateforme, mais le développement se fait sur une véritable plate-forme. Depuis GCC prend en charge cette extension, je pense, la vraie réponse à votre question est qu'il n'est pas intéressé dans la promotion de ce type de fonction en C++ Standard.

Du point de vue pratique, comprenant des protections causé notre équipe de plus de problèmes que l'conforme de la directive #pragma une fois. Par exemple, GUID citer les gardes ne pas l'aider en cas si le fichier est dupliqué et plus tard, les deux copies sont inclus. Lorsque vous utilisez seulement une fois #pragma nous obtenir un double définition de l'erreur et peuvent passer du temps à unifier le code source. Mais dans le cas d'inclure des gardes le problème peut exiger l'exécution de tests pour les attraper, comme par exemple ce qui se passe si les copies diffèrent dans les arguments par défaut pour les paramètres de la fonction.

- Je éviter d'inclure des gardes. Si j'ai de port mon code pour un compilateur sans #pragma once de soutien, je vais écrire un script qui va ajouter comprenant des protections pour tous les fichiers d'en-tête.

4voto

Pete Kirkham Points 32484

Le problème se produit lorsque vous avez les en-têtes avec le même nom de fichier dans les répertoires différents.

Vous avez donc deux en-têtes qui sont tous deux appelés ice_cream_maker.h dans votre projet, qui ont tous deux une classe appelée ice_cream_maker défini dans les qui remplit la même fonction? Ou faites-vous appel à toutes les classes de votre système d' foo?

Néanmoins, la définition est inclus une fois, compilateur encore ouvre-tête à chaque fois qu'il se réunit en-tête de l'inclusion.

Modifier le code afin de ne pas inclure les en-têtes plusieurs fois.

Charge pour les en-têtes (plutôt que de l'en-tête principal pour une bibliothèque), j'ai souvent utiliser l'en-tête des gardes qui sont comme ceci:

#ifdef FOO_BAR_BAZ_H
#error foo_bar_baz.h multiply included
#else
#define FOO_BAR_BAZ_H

// header body

#endif

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