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

Oct 23 2008

In C ++ ist es üblich, Mitgliedsvariablen mit einem Präfix zu benennen, um die Tatsache anzuzeigen, dass es sich um Mitgliedsvariablen handelt und nicht um lokale Variablen oder Parameter. Wenn Sie aus einem MFC-Hintergrund stammen, werden Sie wahrscheinlich verwenden m_foo. Ich habe auch myFoogelegentlich 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?

Antworten

868 24revs,13users35%RogerPate Oct 23 2008 at 14:08

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

  • In jedem Bereich reserviert, auch zur Verwendung als Implementierungsmakros :
    • Bezeichner, die mit einem Unterstrich beginnen, unmittelbar gefolgt von einem Großbuchstaben
    • Bezeichner mit benachbarten Unterstrichen (oder "doppeltem Unterstrich")
  • Reserviert im globalen Namespace:
    • Bezeichner, die mit einem Unterstrich beginnen
  • Außerdem ist alles im stdNamespace reserviert. (Sie können jedoch Vorlagenspezialisierungen hinzufügen.)

Aus 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 der Implementierung für jede Verwendung vorbehalten.
  • Jeder Name, der mit einem Unterstrich beginnt, ist der Implementierung zur Verwendung als Name im globalen Namespace vorbehalten. 165

165) Solche Namen sind auch im Namespace ::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 von 1999:

7.1.3 Reservierte Kennungen

Jeder Header deklariert oder definiert alle in seinem zugeordneten Unterabschnitt aufgelisteten Bezeichner und deklariert oder definiert optional Bezeichner, die in seinem zugeordneten zukünftigen Bibliotheksanweisungsunterabschnitt und Bezeichnern aufgeführt sind, die immer entweder für eine Verwendung oder zur 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 jede 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 wie angegeben reserviert, 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.

Es sind keine anderen Bezeichner 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 #undefeine Makrodefinition eines Bezeichners in der ersten oben aufgeführten Gruppe entfernt (mit ), ist das Verhalten undefiniert.

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

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

  • Namen, die mit einem Großbuchstaben beginnen, Efolgten einer Ziffer oder einem Großbuchstaben:
    • kann für zusätzliche Fehlercode-Namen verwendet werden.
  • Namen, die entweder mit isoder togefolgt von einem Kleinbuchstaben beginnen
    • kann für zusätzliche Zeichentest- und Konvertierungsfunktionen verwendet werden.
  • Namen, die mit LC_einem Großbuchstaben beginnen
    • kann für zusätzliche Makros verwendet werden, die Gebietsschemaattribute angeben.
  • Namen aller vorhandenen mathematischen Funktionen, denen ein Suffix beigefügt ist foder ldie reserviert sind
    • für entsprechende Funktionen, die mit float- bzw. langen Doppelargumenten arbeiten.
  • Namen, die mit SIGeinem Großbuchstaben beginnen, sind reserviert
    • für zusätzliche Signalnamen.
  • Namen, die mit SIG_einem Großbuchstaben beginnen, sind reserviert
    • für zusätzliche Signalaktionen.
  • Namen, die mit str, memoder wcsgefolgt von einem Kleinbuchstaben beginnen, sind reserviert
    • für zusätzliche String- und Array-Funktionen.
  • Namen, die mit einem Kleinbuchstaben beginnen PRIoder von diesem SCNgefolgt werden, Xsind reserviert
    • für zusätzliche Formatbezeichner-Makros
  • Namen, die mit enden, _tsind reserviert
    • für zusätzliche Typnamen.

Obwohl die Verwendung dieser Namen für Ihre eigenen Zwecke im Moment möglicherweise kein Problem darstellt, besteht die Möglichkeit eines Konflikts mit zukünftigen Versionen dieses Standards.


Persönlich beginne ich Bezeichner 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, _tda dies dem POSIX-Standard vorbehalten ist.

Die Regel, dass ein Bezeichner mit endet _t, hat mich sehr überrascht. Ich denke, das ist ein POSIX-Standard (noch nicht sicher), der nach Klarstellung und offiziellem Kapitel und Vers sucht. Dies ist aus dem GNU libtool-Handbuch , in dem reservierte Namen aufgeführt sind.

CesarB stellte den folgenden Link zu den reservierten POSIX 2004- Symbolen und Notizen bereit , "dass viele andere reservierte Präfixe und Suffixe ... dort zu finden sind". Hier werden die reservierten POSIX 2008- Symbole definiert. Die Einschränkungen sind etwas differenzierter als die oben genannten.

202 paercebal Oct 23 2008 at 14:27

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 wollte, habe ich eine persönliche Regel entworfen , die sowohl einfach als auch korrekt ist:

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

  • Beginnen Sie ein Symbol niemals mit einem Unterstrich
  • Nennen Sie niemals ein Symbol mit zwei aufeinander folgenden Unterstrichen.

Wenn Sie Ihren Code in einen eindeutigen Namespace einfügen, können Sie natürlich auch Kollisionen vermeiden (schützt jedoch nicht vor bösen Makros).

Einige Beispiele

(Ich verwende Makros, weil sie die C / C ++ - Symbole stärker durch Code verschmutzen, aber es kann alles sein, vom Variablennamen bis zum Klassennamen.)

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

Auszüge aus dem 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 der Implementierung für jede Verwendung vorbehalten.

- Jeder Name, der mit einem Unterstrich beginnt, ist der Implementierung zur Verwendung als Name im globalen Namespace vorbehalten.

Aber auch:

17.6.3.3.5 Benutzerdefinierte Literal-Suffixe [usrlit.suffix]

Literale 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 sind der Meinung, dass ein Name, der mit einem Unterstrich beginnt und auf den ein Kleinbuchstabe folgt, in Ordnung wäre, wenn er nicht im globalen Namespace definiert wäre ...

40 RogerLipscombe Oct 23 2008 at 14:06

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 vermeiden, einen führenden Unterstrich gefolgt von einem Kleinbuchstaben für Namen mit Dateibereich zu verwenden, da möglicherweise Konflikte mit aktuellen oder zukünftigen reservierten Bezeichnern auftreten.

Dies bedeutet, dass Sie einen einzelnen Unterstrich als Präfix für eine Mitgliedsvariable verwenden können, sofern ein Kleinbuchstabe folgt.

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 .

25 MaxLybbert Nov 15 2008 at 03:03

Was den anderen Teil der Frage betrifft, ist es üblich, den Unterstrich am Ende des Variablennamens zu setzen, um nicht mit internen Elementen 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").

1 JohnMillikin Oct 23 2008 at 14:05

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

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