Ist #pragma einmal Teil des C ++ 11-Standards?

140

Traditionell war / ist die standardmäßige und tragbare Methode zur Vermeidung mehrerer Header-Einschlüsse in C ++ die Verwendung des #ifndef - #define - #endifPre-Compiler-Direktiven-Schemas, das auch als Makro-Guard-Schema bezeichnet wird (siehe Code-Snippet unten).

#ifndef MY_HEADER_HPP
#define MY_HEADER_HPP
...
#endif

In den meisten Implementierungen / Compilern (siehe Bild unten) gibt es jedoch eine "elegantere" Alternative, die denselben Zweck erfüllt wie das aufgerufene Makro-Guard-Schema #pragma once. #pragma oncehat im Vergleich zum Makro-Guard-Schema mehrere Vorteile, darunter weniger Code, die Vermeidung von Namenskonflikten und manchmal eine verbesserte Kompilierungsgeschwindigkeit.

Geben Sie hier die Bildbeschreibung ein

Bei einigen Nachforschungen stellte ich fest, dass die #pragma onceDirektive zwar von fast allen bekannten Compilern unterstützt wird, es jedoch eine Unklarheit darüber gibt, ob die #pragma onceDirektive Teil des C ++ 11-Standards ist oder nicht.

Fragen:

  • Könnte jemand klären, ob die #pragma onceDirektive Teil des C ++ 11-Standards ist oder nicht?
  • Wenn es nicht Teil des C ++ 11-Standards ist, gibt es Pläne, es in späteren Versionen (z. B. C ++ 14 oder höher) aufzunehmen?
  • Es wäre auch schön, wenn jemand die Vor- und Nachteile bei der Verwendung einer der beiden Techniken (dh Makroschutz gegenüber #pragma once) weiter erläutern könnte .
101010
quelle
9
Im Übrigen ist die Verwendung von doppelten Unterstrichen für die Kopfschutzvorrichtungen durch den Standard verboten, der für die Implementierung alle Symbole reserviert, die mit einem doppelten Unterstrich beginnen (neben anderen).
Matteo Italia
9
Die Verwendung eines führenden Unterstrichs gefolgt von einem Großbuchstaben ist ebenfalls ausgeschlossen. Zweitens, wo ist die Trübung? Ich sehe nur Compiler-Unterstützung. Ich sehe niemanden, der behauptet, es sei Teil des Standards.
Yakk - Adam Nevraumont
1
Schauen Sie sich für den dritten Punkt die verwandte Frage an: Ist #pragma einmal ein sicherer Include-Wächter? Es gab eine Situation, in der Header Guards funktionieren, aber #pragma oncenormalerweise nicht.
user1942027
1
Mögliches Duplikat, indem es diese Frage beantwortet, ohne C ++ 11 zu erwähnen.
Yakk - Adam Nevraumont
3
Nun, es ist in keinem offiziellen Dokument kodiert, aber Sie können es als De-facto- Standard betrachten.
Siyuan Ren

Antworten:

107

#pragma onceist nicht Standard. Es ist eine weit verbreitete (aber nicht universelle) Erweiterung, die verwendet werden kann

  • wenn Ihre Portabilitätsbedenken begrenzt sind, und
  • Sie können sicher sein, dass sich alle Include-Dateien immer auf einer lokalen Festplatte befinden.

Es wurde für die Standardisierung in Betracht gezogen, aber abgelehnt, da es nicht zuverlässig implementiert werden kann. (Die Probleme treten auf, wenn Sie über Dateien verfügen, auf die über verschiedene Remote-Bereitstellungen zugegriffen werden kann.)

Es ist ziemlich einfach sicherzustellen, dass es innerhalb einer einzelnen Entwicklung keine Include-Guard-Konflikte gibt. Für Bibliotheken, die von vielen verschiedenen Entwicklungen verwendet werden können, besteht die offensichtliche Lösung darin, beim Erstellen viele zufällige Zeichen für den Include Guard zu generieren. (Ein guter Editor kann eingerichtet werden, um dies für Sie zu tun, wenn Sie einen neuen Header öffnen.) Aber auch ohne dies habe ich noch keine Probleme mit Konflikten zwischen Bibliotheken.

James Kanze
quelle
11
Nicht nur Fernmontagen. Hardlinks, Softlinks, Subst-Konstrukte (unter Windows). Es kann sehr chaotisch werden.
Tonny
45
Warum kann der Compiler keine SHA-1- oder MD5-Prüfsummen verwenden, um die Dateien zu identifizieren?
Sergey
29
Ich sehe es wirklich nicht als sinnvoll an, etwas nicht in den Standard aufzunehmen, wenn jeder große Compiler dies unterstützt. Es gibt Dinge im Standard, die weit weniger unterstützt werden. Außerdem scheint es ziemlich dumm zu sein, sich über Edge-Probleme zu beschweren, wenn es um Include-Dateien geht, bei denen Dateinamenkonflikte bereits ein großes Problem darstellen. Es wäre schön gewesen, wenn diese Forderung nach einer 100% problemlosen Funktion auf das Konzept der # eingeschlossenen Header-Dateien im Allgemeinen angewendet worden wäre.
TED
38
Wenn Ihr Code eine Datei von verschiedenen Speicherorten über symbolische Links oder seltsame Bereitstellungen enthält, ist er bereits nicht portierbar. Daher ist das Argumentieren, dass pragma onceetwas, das von Natur aus nicht portabel ist (und nicht einmal in Betracht gezogen werden sollte) , nicht portabel implementiert werden kann, ein weiterer Unsinn der verkehrten C ++ - Welt.
Doc
7
@JoseAntonioDuraOlmos Ich stimme zu, dass symbolische Links eine Betriebssystemfunktion sind, die außerhalb des Bereichs der C ++ - Sprache liegt. Daher stellt sich die Frage, warum das C ++ - Komitee etwas in Betracht ziehen sollte, das außerhalb des Geltungsbereichs der Sprache liegt. Der Versuch, etwas zu garantieren, für das sie nicht verantwortlich sind, macht IMO keinen Sinn. DOS hat nur 8 + 3 Zeichen pro Dateiname unterstützt, aber niemand hat argumentiert, dass #includedies entfernt werden muss, da man die Direktive blind missbrauchen kann. #pragma onceschränkt die Portabilität in keiner Weise ein, vorausgesetzt, Sie nutzen keine symbolischen Links, um die Kompilierung zu unterbrechen.
Doc
32

Abschnitt §16.6 des Standards ( Entwurf N3936 ) beschreibt #pragmaRichtlinien wie folgt :

Eine Vorverarbeitungsanweisung des Formulars

# pragma pp-tokensopt new-line

bewirkt, dass sich die Implementierung implementierungsdefiniert verhält. Das Verhalten kann dazu führen, dass die Übersetzung fehlschlägt oder dass sich der Übersetzer oder das resultierende Programm nicht konform verhält. Jedes Pragma, das von der Implementierung nicht erkannt wird, wird ignoriert.

Grundsätzlich #pragma oncehandelt es sich um eine implementierungsspezifische Instanz einer #pragmaDirektive, und nein, sie ist kein Standard. Noch.

Es wird häufig von den meisten "großen Compilern", einschließlich GCC und Clang, weitgehend unterstützt und wird daher manchmal empfohlen, um das Boilerplate von Include-Guards zu vermeiden.

Schuh
quelle
10
Beachten Sie, dass Sie beide #pragmaund #defineHeader-Guard können.
Yakk - Adam Nevraumont
18
"Jedes Pragma, das von der Implementierung nicht erkannt wird, wird ignoriert" . Bedeutet dies, dass die Meldung: Warnung: Nicht erkannte Pragma-Direktive nicht konform ist?
Rodrigo
6
"und ist daher der empfohlene Weg, um das Boilerplate von Include-Guards zu vermeiden" - eine sehr kühne Aussage. Es ist ein nicht standardmäßiger Weg, und die Vorteile der Verwendung sind gering und für meine Erfahrung kaum relevant, so dass ich meine +1 wegnehmen musste.
Alex
19
@Yakk: Wenn jemand #defineHeader-Guard schreibt , hat er / sie KEINEN Grund, ebenfalls zu schreiben #pragma once.
Nawaz
5
@Nawaz Ein Compiler kann einen Cache für jede Datei (nach Pfad) behalten, die #pragma onced war, und im Falle, dass es #includewieder d ist, kann er das überspringen #include(nicht einmal die Datei öffnen). gcc macht dasselbe mit Header Guards, aber es ist sehr, sehr zerbrechlich. Der #pragmaeine ist einfach zu machen, der Kopfschutz ist schwer.
Yakk - Adam Nevraumont