#Pragma fait-il autrefois partie de la norme C ++ 11?

140

Traditionnellement, le moyen standard et portable d'éviter les inclusions d'en-têtes multiples en C ++ était / consiste à utiliser le #ifndef - #define - #endifschéma de directives pré-compilateur également appelé schéma de macro-garde (voir l'extrait de code ci-dessous).

#ifndef MY_HEADER_HPP
#define MY_HEADER_HPP
...
#endif

Dans la plupart des implémentations / compilateurs (voir l'image ci-dessous) cependant, il existe une alternative plus "élégante" qui sert le même objectif que le schéma de macro-garde appelé #pragma once. #pragma onceprésente plusieurs avantages par rapport au schéma de macro-garde, notamment moins de code, éviter les conflits de noms et parfois une vitesse de compilation améliorée.

entrez la description de l'image ici

En faisant quelques recherches, je me suis rendu compte que, bien que la #pragma oncedirective soit prise en charge par presque tous les compilateurs connus, il y a une incertitude quant à savoir si la #pragma oncedirective fait partie du standard C ++ 11 ou non.

Des questions:

  • Quelqu'un pourrait-il clarifier si la #pragma oncedirective fait partie du standard C ++ 11 ou non?
  • S'il ne fait pas partie de la norme C ++ 11, est-il prévu de l'inclure dans les versions ultérieures (par exemple, C ++ 14 ou version ultérieure)?
  • Ce serait également bien si quelqu'un pouvait développer davantage les avantages / inconvénients de l'utilisation de l'une ou l'autre des techniques (c.-à-d. Macro-garde contre #pragma once).
101010
la source
9
Incidemment, l'utilisation de doubles traits de soulignement pour les gardes d'en-tête est interdite par la norme, qui réserve pour l'implémentation tous les symboles commençant par un double trait de soulignement (en plus d'autres).
Matteo Italia
9
L'utilisation d'un trait de soulignement avant suivi d'une majuscule est également interdite. Deuxièmement, où est la turbidité? Je vois juste le support du compilateur, je ne vois personne prétendant qu'il fait partie de la norme?
Yakk - Adam Nevraumont
1
Pour le troisième point, regardez la question connexe: #pragma est-il autrefois un garde sûr? Il y a une situation où les gardes d'en-tête fonctionnent mais #pragma oncegénéralement pas.
user1942027
1
doublon possible en ce qu'il répond à cette question sans mentionner C ++ 11.
Yakk - Adam Nevraumont
3
Eh bien, il n'est codé dans aucun document officiel, mais vous pouvez le considérer comme une norme de facto .
Siyuan Ren

Réponses:

107

#pragma oncen'est pas standard. C'est une extension répandue (mais pas universelle), qui peut être utilisée

  • si vos problèmes de portabilité sont limités, et
  • vous pouvez être sûr que tous vos fichiers d'inclusion sont toujours sur un disque local.

Il a été envisagé pour la normalisation, mais rejeté car il ne peut pas être mis en œuvre de manière fiable. (Les problèmes se produisent lorsque vous avez des fichiers accessibles via plusieurs montages distants différents.)

Il est assez facile de s'assurer qu'il n'y a pas de conflits d'inclusion de garde dans un seul développement. Pour les bibliothèques, qui peuvent être utilisées par de nombreux développements différents, la solution évidente est de générer beaucoup de caractères aléatoires pour la garde d'inclusion lorsque vous la créez. (Un bon éditeur peut être configuré pour le faire pour vous chaque fois que vous ouvrez un nouvel en-tête.) Mais même sans cela, je n'ai pas encore rencontré de problèmes de conflits entre bibliothèques.

James Kanze
la source
11
Pas seulement des montages à distance. Hardlinks, softlinks, sous-constructions (sous Windows). Cela peut devenir vraiment compliqué.
Tonny
45
Pourquoi le compilateur ne peut-il pas utiliser les sommes de contrôle SHA-1 ou MD5 pour identifier les fichiers?
Sergey
29
Je ne vois vraiment pas l'intérêt de ne pas mettre quelque chose dans le standard si tous les compilateurs majeurs le supportent. Il y a en fait des choses dans la norme beaucoup moins supportées que cela. En outre, il semble assez idiot de se plaindre des problèmes de périphérie, lorsque nous parlons de fichiers d'inclusion, où les conflits de noms de fichiers sont déjà un énorme problème. Cela aurait été bien si cette demande d'une fonctionnalité 100% sans problème avait été appliquée au concept de fichiers d'en-tête #included en général.
TED
38
Si votre code comprend des fichiers provenant d'emplacements différents via des liens symboliques ou des montages étranges, il n'est déjà pas portable. Par conséquent, argumenter que pragma oncene peut pas implémenter de manière portative quelque chose qui n'est pas en soi portable (et ne devrait même pas être considéré) est encore un autre non-sens du monde à l'envers du C ++.
doc
7
@JoseAntonioDuraOlmos Je suis d'accord que les liens symboliques sont une fonctionnalité du système d'exploitation, qui est hors du champ d'application du langage C ++. Par conséquent, la question se pose de savoir pourquoi le comité C ++ devrait envisager quelque chose qui est hors de portée du langage? Essayer de garantir quelque chose qui n'est pas de leur responsabilité n'a aucun sens IMO. DOS n'a pris en charge que 8 + 3 caractères par nom de fichier, mais personne n'a soutenu que cela #includedevait être supprimé, car on peut abuser aveuglément de la directive. #pragma oncene limite en aucune façon la portabilité, à condition que vous n'utilisiez pas les liens symboliques pour interrompre la compilation.
doc
32

La section §16.6 de la norme ( projet N3936 ) décrit les #pragmadirectives comme:

Une directive de prétraitement du formulaire

# pragma pp-tokensopt new-line

fait en sorte que l'implémentation se comporte d'une manière définie par l'implémentation. Le comportement peut entraîner l'échec de la traduction ou entraîner un comportement non conforme du traducteur ou du programme résultant. Tout pragma non reconnu par l'implémentation est ignoré.

Fondamentalement, il #pragma onces'agit d'une instance spécifique de mise en œuvre d'une #pragmadirective, et non, ce n'est pas standard. Encore.

Il est souvent largement supporté par la plupart des "grands compilateurs", y compris GCC et Clang, et il est donc parfois recommandé d'éviter le passe-partout d'inclusion-gardes.

Chaussure
la source
10
Notez que vous pouvez à la fois #pragmaet #definehead-guard.
Yakk - Adam Nevraumont
18
"Tout pragma non reconnu par l'implémentation est ignoré" . Cela signifie-t-il que le message: Attention: la directive pragma non reconnue n'est pas conforme?
rodrigo
6
"et est donc le moyen recommandé d'éviter le passe-partout" inclus-gardes "- une déclaration très audacieuse. C'est un moyen non standard, et les avantages de son utilisation sont rares et n'ont guère été pertinents dans mon expérience, j'ai donc dû retirer mon +1.
Alex
19
@Yakk: Si quelqu'un écrit #defineen-tête-garde, il / elle n'a AUCUNE raison d'écrire #pragma onceaussi.
Nawaz
5
@Nawaz Un compilateur peut garder un cache de chaque fichier (par chemin) qui a été #pragma onced, et dans le cas où il est à #includenouveau d peut sauter le #include(pas même ouvrir le fichier). gcc fait la même chose avec les protections d'en-tête, mais il est très, très fragile. Celui #pragmaest facile à faire, celui du garde-tête est dur.
Yakk - Adam Nevraumont