it-swarm.com.de

Welche Regeln gelten für die Verwendung eines Unterstrichs in einem C ++ - Bezeichner?

In C++ ist es üblich, Mitgliedsvariablen mit einem Präfix zu benennen, um die Tatsache zu kennzeichnen, dass es sich um Mitgliedsvariablen handelt, und nicht um lokale Variablen oder Parameter. Wenn Sie aus einem MFC-Hintergrund stammen, werden Sie wahrscheinlich m_foo verwenden. Ich habe auch gelegentlich myFoo gesehen.

C # (oder möglicherweise nur .NET) scheint zu empfehlen, nur einen Unterstrich zu verwenden, wie in _foo. Ist dies nach dem C++ - Standard zulässig?

891
Roger Lipscombe

Die Regeln (die sich in C++ 11 nicht geändert haben):

  • In jedem Bereich reserviert, auch zur Verwendung als Implementierung Makros:
    • bezeichner, die mit einem Unterstrich beginnen, gefolgt von einem Großbuchstaben
    • bezeichner, die benachbarte Unterstriche (oder "doppelte Unterstriche") enthalten
  • Reserviert im globalen Namespace:
    • bezeichner, die mit einem Unterstrich beginnen
  • Außerdem ist alles im Namespace std reserviert. (Sie können jedoch Vorlagen-Spezialisierungen hinzufügen.)

Ab dem C++ Standard 2003:

17.4.3.1.2 Globale Namen [lib.global.names]

Bestimmte Sätze von Namen und Funktionssignaturen sind immer der Implementierung vorbehalten:

  • Jeder Name, der einen doppelten Unterstrich (__) enthält oder mit einem Unterstrich gefolgt von einem Großbuchstaben (2.11) beginnt, ist für die Implementierung für jegliche Verwendung reserviert.
  • Jeder Name, der mit einem Unterstrich beginnt, ist für die Implementierung zur Verwendung als Name im globalen Namespace reserviert.165

165) Solche Namen sind auch im Namensraum ::std (17.4.3.1) reserviert.

Da C++ auf dem C-Standard (1.1/2, C++ 03) basiert und C99 eine normative Referenz (1.2/1, C++ 03) ist, gelten diese auch ab dem C-Standard 1999:

7.1.3 Reservierte Kennungen

Jeder Header deklariert oder definiert alle in der zugehörigen Unterklausel aufgelisteten Bezeichner und deklariert oder definiert optional die in der zugehörigen Unterklausel für zukünftige Bibliotheksanweisungen aufgelisteten Bezeichner und Bezeichner, die immer entweder für die Verwendung oder für die Verwendung als Dateibereichsbezeichner reserviert sind.

  • Alle Bezeichner, die mit einem Unterstrich und entweder einem Großbuchstaben oder einem anderen Unterstrich beginnen, sind immer für die Verwendung reserviert.
  • Alle Bezeichner, die mit einem Unterstrich beginnen, sind immer für die Verwendung als Bezeichner mit Dateibereich sowohl im normalen als auch im Tag-Namensraum reserviert.
  • Jeder Makroname in einem der folgenden Unterabschnitte (einschließlich der zukünftigen Bibliotheksanweisungen) ist für die Verwendung reserviert, wie angegeben, wenn einer der zugehörigen Header enthalten ist. sofern nicht ausdrücklich anders angegeben (siehe 7.1.4).
  • Alle Bezeichner mit externer Verknüpfung in einem der folgenden Unterabschnitte (einschließlich der zukünftigen Bibliotheksanweisungen) sind immer für die Verwendung als Bezeichner mit externer Verknüpfung reserviert.154
  • Jeder Bezeichner mit Dateibereich, der in einem der folgenden Unterabschnitte aufgeführt ist (einschließlich der zukünftigen Bibliotheksanweisungen), ist für die Verwendung als Makroname und als Bezeichner mit Dateibereich im selben Namensraum reserviert, wenn einer der zugehörigen Header enthalten ist.

Andere Bezeichner sind nicht reserviert. Wenn das Programm einen Bezeichner in einem Kontext deklariert oder definiert, in dem er reserviert ist (anders als in 7.1.4 zulässig), oder einen reservierten Bezeichner als Makronamen definiert, ist das Verhalten undefiniert.

Wenn das Programm (mit #undef) eine Makrodefinition eines Bezeichners in der ersten oben aufgeführten Gruppe entfernt, ist das Verhalten undefiniert.

154) Die Liste der reservierten Bezeichner mit externer Verknüpfung enthält errno, math_errhandling, setjmp und va_end.

Möglicherweise gelten andere Einschränkungen. Zum Beispiel reserviert der POSIX-Standard viele Bezeichner, die wahrscheinlich im normalen Code angezeigt werden:

  • Namen, die mit einem Großbuchstaben E beginnen, folgen einer Ziffer oder einem Großbuchstaben:
    • kann für zusätzliche Fehlercodenamen verwendet werden.
  • Namen, die entweder mit is oder to beginnen, gefolgt von einem Kleinbuchstaben
    • kann für zusätzliche Funktionen zum Testen und Konvertieren von Zeichen verwendet werden.
  • Namen, die mit LC_ beginnen, gefolgt von einem Großbuchstaben
    • kann für zusätzliche Makros verwendet werden, die Gebietsschemaattribute angeben.
  • Die Namen aller vorhandenen mathematischen Funktionen mit dem Zusatz f oder l sind reserviert
    • für entsprechende Funktionen, die mit Float- bzw. langen Doppelargumenten arbeiten.
  • Namen, die mit SIG beginnen, gefolgt von einem Großbuchstaben, sind reserviert
    • für zusätzliche Signalnamen.
  • Namen, die mit SIG_ beginnen, gefolgt von einem Großbuchstaben, sind reserviert
    • für zusätzliche Signalaktionen.
  • Namen, die mit str, mem oder wcs beginnen, gefolgt von einem Kleinbuchstaben, sind reserviert
    • für zusätzliche String- und Array-Funktionen.
  • Namen, die mit PRI oder SCN beginnen, gefolgt von Kleinbuchstaben oder X, sind reserviert
    • für zusätzliche Formatbezeichner-Makros
  • Namen, die mit _t enden, sind reserviert
    • für zusätzliche Typnamen.

Obwohl die Verwendung dieser Namen für Ihre eigenen Zwecke im Moment möglicherweise kein Problem darstellt, kann es zu Konflikten mit zukünftigen Versionen dieses Standards kommen.


Persönlich beginne ich Identifikatoren einfach nicht mit Unterstrichen. Neu in meiner Regel: Verwenden Sie nirgendwo doppelte Unterstriche, was einfach ist, da ich selten Unterstriche verwende.

Nachdem ich diesen Artikel recherchiert habe, beende ich meine Bezeichner nicht mehr mit _t, da dies durch den POSIX-Standard reserviert ist.

Die Regel, dass ein Bezeichner mit _t endet, hat mich sehr überrascht. Ich denke, das ist ein POSIX-Standard (noch nicht sicher), der Klarheit und offizielle Kapitel und Verse sucht. Dies ist aus dem GNU libtool manual , das reservierte Namen auflistet.

CesarB hat den folgenden Link zu den POSIX 2004 reservierten Symbolen und Hinweisen bereitgestellt, "die viele andere reservierte Präfixe und Suffixe ... dort finden". Die POSIX 2008 reservierten Symbole werden hier definiert. Die Einschränkungen sind etwas differenzierter als die oben genannten.

809
Martin York

Die Regeln zur Vermeidung von Namenskollisionen sind sowohl im C++ - Standard (siehe Stroustrup-Buch) als auch von C++ - Gurus (Sutter usw.) erwähnt.

Persönliche Regel

Da ich mich nicht mit Fällen befassen wollte und eine einfache Regel haben wollte, habe ich eine persönliche entworfen, die sowohl einfach als auch korrekt ist:

Wenn Sie ein Symbol benennen, vermeiden Sie Kollisionen mit Compiler-/OS-/Standardbibliotheken, wenn Sie:

  • beginnen Sie ein Symbol niemals mit einem Unterstrich
  • nennen Sie niemals ein Symbol mit zwei aufeinanderfolgenden Unterstrichen.

Natürlich hilft das Einfügen Ihres Codes in einen eindeutigen Namespace auch dabei, Kollisionen zu vermeiden (schützt jedoch nicht vor bösen Makros).

Einige Beispiele

(Ich verwende Makros, weil sie den Code von C/C++ - Symbolen stärker verschmutzen, aber es kann sich um alles handeln, von Variablennamen bis Klassennamen.)

#define _WRONG
#define __WRONG_AGAIN
#define RIGHT_
#define WRONG__WRONG
#define RIGHT_RIGHT
#define RIGHT_x_RIGHT

Auszüge aus C++ 0x Entwurf

Aus der Datei n3242.pdf (ich erwarte, dass der endgültige Standardtext ähnlich ist):

17.6.3.3.2 Globale Namen [global.names]

Bestimmte Sätze von Namen und Funktionssignaturen sind immer der Implementierung vorbehalten:

- Jeder Name, der einen doppelten Unterstrich _ _ enthält oder mit einem Unterstrich gefolgt von einem Großbuchstaben (2.12) beginnt, ist für die Implementierung für die Verwendung reserviert.

- Jeder Name, der mit einem Unterstrich beginnt, ist für die Implementierung zur Verwendung als Name im globalen Namespace reserviert.

Aber auch:

17.6.3.3.5 Benutzerdefinierte Literal-Suffixe [usrlit.suffix]

Literal-Suffix-IDs, die nicht mit einem Unterstrich beginnen, sind für die zukünftige Standardisierung reserviert.

Diese letzte Klausel ist verwirrend, es sei denn, Sie meinen, ein Name, der mit einem Unterstrich und einem Kleinbuchstaben beginnt, wäre Ok if nicht im globalen Namensraum definiert ...

189
paercebal

Von MSDN :

Die Verwendung von zwei aufeinander folgenden Unterstrichen (__) am Anfang eines Bezeichners oder eines einzelnen führenden Unterstrichs, gefolgt von einem Großbuchstaben, ist für C++ - Implementierungen in allen Bereichen reserviert. Sie sollten es vermeiden, einen führenden Unterstrich gefolgt von einem Kleinbuchstaben für Namen mit Dateibereich zu verwenden, da dies zu Konflikten mit aktuellen oder zukünftigen reservierten Bezeichnern führen kann.

Dies bedeutet, dass Sie einen einzelnen Unterstrich als Präfix für eine Mitgliedsvariable verwenden können, sofern dieser von einem Kleinbuchstaben gefolgt wird.

Dies stammt anscheinend aus Abschnitt 17.4.3.1.2 des C++ - Standards, aber ich kann online keine Originalquelle für den vollständigen Standard finden.

Siehe auch diese Frage .

35
Roger Lipscombe

Was den anderen Teil der Frage betrifft, ist es üblich, den Unterstrich an das Ende des Variablennamens zu setzen, um nicht mit irgendetwas Internem in Konflikt zu geraten.

Ich mache das sogar innerhalb von Klassen und Namespaces, weil ich mich dann nur an eine Regel erinnern muss (im Vergleich zu "am Ende des Namens im globalen Bereich und am Anfang des Namens überall sonst").

23
Max Lybbert

Ja, Unterstriche können überall in einem Bezeichner verwendet werden. Ich glaube, die Regeln lauten: a-z, A-Z, _ im ersten Zeichen und diese + 0-9 für die folgenden Zeichen.

Präfixe für Unterstriche sind in C-Code üblich - ein einzelner Unterstrich bedeutet "privat", und doppelte Unterstriche sind normalerweise für die Verwendung durch den Compiler reserviert.

3
John Millikin