Jakie są zasady używania podkreślenia w identyfikatorze C++?

W C++ często nazywa się zmienne członkowskie jakimś prefiksem określającym fakt, że są to zmienne członkowskie, a nie zmienne lokalne lub parametry. Jeśli pochodzisz z tła MFC, prawdopodobnie użyjesz m_foo. Widziałem też myFoo okazjonalnie.

C #(lub ewentualnie po prostu. NET) wydaje się zalecać używanie tylko podkreślenia, jak w _foo. Czy jest to dozwolone przez standard C++?

Author: Taryn, 2008-10-23

5 answers

Zasady (które nie zmieniły się w C++11):

  • zastrzeżone w dowolnym zakresie, w tym do wykorzystania jako makra implementacyjne:
    • identyfikatory rozpoczynające się podkreśleniem, a następnie od razu wielką literą
    • identyfikatory zawierające sąsiadujące podkreślniki (lub"podwójny podkreślnik")
  • zarezerwowane w globalnej przestrzeni nazw:
    • identyfikatory zaczynające się od podkreślenia
  • również wszystko w std przestrzeni nazw jest zastrzeżone. (Możesz jednak dodawać specjalizacje szablonów.)

Ze standardu C++ z 2003 roku:

17.4.3.1.2 nazwy Globalne [lib.global.nazwy]

Niektóre zbiory nazw i podpisów funkcji są zawsze zarezerwowane dla implementacji:]}
  • każda nazwa, która zawiera podwójny podkreślnik (__) lub zaczyna się podkreślnikiem, po którym następuje wielka litera (2.11), jest zarezerwowana dla implementacji do dowolnego użycia.
  • każda nazwa zaczynająca się od podkreślenia jest zarezerwowana dla implementacji do użycia jako nazwa w globalnej przestrzeni nazw.165

165) nazwy takie są również zarezerwowane w przestrzeni nazw ::std (17.4.3.1).

Ponieważ C++ jest oparty na standardzie C (1.1/ 2, C++03) i C99 jest odniesieniem normatywnym (1.2/1, C++03), stosuje się je również od standardu C 1999:

7.1.3 zarezerwowane identyfikatory

Każdy nagłówek deklaruje lub definiuje wszystkie identyfikatory wymienione w powiązanej podkluczy, oraz opcjonalnie deklaruje lub definiuje identyfikatory wymienione w powiązanej z nimi przyszłej instrukcji bibliotecznej oraz identyfikatory, które są zawsze zarezerwowane do dowolnego wykorzystania lub do wykorzystania jako identyfikatory zakresu plików.

  • wszystkie identyfikatory zaczynające się od podkreślenia i wielkiej litery lub innej podkreślenia są zawsze zarezerwowane do dowolnego użytku.
  • wszystkie identyfikatory zaczynające się od podkreślenia są zawsze zarezerwowane do wykorzystania jako identyfikatory z zakresem plików zarówno w zwykłych, jak i nazwach znaczników.
  • nazwa każdego makra w jednej z następujących podklauz (łącznie z przyszłą biblioteką directions) jest zarezerwowany do użycia, jak określono, jeśli którykolwiek z powiązanych nagłówków jest dołączony; o ile wyraźnie nie zaznaczono inaczej (zob. 7.1.4).
  • wszystkie identyfikatory z linkami zewnętrznymi w jednej z następujących podklas (w tym przyszłych kierunków bibliotecznych) są zawsze zarezerwowane do wykorzystania jako identyfikatory z zewnętrznymi linkage.154
  • każdy identyfikator z zakresem pliku wymienionym w jednej z następujących podklas (w tym przyszłe kierunki bibliotek) jest zarezerwowany do użycia jako nazwa makra i jako identyfikator z zakres pliku w tej samej przestrzeni nazw, jeśli którykolwiek z powiązanych nagłówków jest dołączony.

Żadne inne identyfikatory nie są zastrzeżone. Jeśli program deklaruje lub definiuje identyfikator w kontekst, w którym jest zarezerwowany (inny niż dozwolony przez 7.1.4), lub definiuje zastrzeżone identyfikator jako nazwa makra, zachowanie jest niezdefiniowane.

Jeśli program usunie (z #undef) dowolną definicję makra identyfikatora w pierwszym Grupa wymieniona powyżej, zachowanie jest niezdefiniowane.

154) lista zastrzeżonych identyfikatorów z powiązaniem zewnętrznym obejmuje errno, math_errhandling, setjmp, i va_end.

Mogą obowiązywać inne ograniczenia. Na przykład standard POSIX rezerwuje wiele identyfikatorów, które są prawdopodobnie pojawi się w normalnym kodzie:

  • Nazwy zaczynające się od wielkiej litery E po cyfrze lub Wielkiej literze:
    • Może być używany dla dodatkowych nazw kodów błędów.
  • Nazwy zaczynające się na is lub to, po których następuje mała litera
    • Może być używany do dodatkowych testów znaków i funkcji konwersji.
  • Nazwy zaczynające się na LC_, po których następuje wielka litera
    • Może być stosowany do dodatkowe makra określające atrybuty lokalne.
  • nazwy wszystkich istniejących funkcji matematycznych zakończone f lub l są zastrzeżone
    • dla odpowiednich funkcji operujących odpowiednio na argumentach float i long double.
  • nazwy rozpoczynające się od SIG, po której następuje wielka litera są zastrzeżone
    • dla dodatkowych nazw sygnałów.
  • Nazwy zaczynające się na SIG_, po których następuje wielka litera są zastrzeżone
    • dla dodatkowych akcji sygnałowych.
  • Nazwy zaczynające się na str, mem, lub wcs, po których następuje mała litera są zarezerwowane
    • dla dodatkowych funkcji typu string i array.
  • nazwy rozpoczynające się od PRI lub SCN, po których następuje mała litera lub X są zarezerwowane
    • dla dodatkowych makr specyfikacji formatu
  • nazwy kończące się na _t są zastrzeżone
    • dla dodatkowe nazwy typów.

Chociaż używanie tych nazw do własnych celów w tej chwili może nie powodować problemu, to jednak podnoszą one możliwość konfliktu z przyszłymi wersjami tego standardu.


Osobiście po prostu nie zaczynam identyfikatorów od podkreślenia. Nowy dodatek do mojej zasady: nie używaj podwójnego podkreślenia nigdzie, co jest łatwe, ponieważ rzadko używam podkreślenia.

Po przeprowadzeniu badań nad tym artykułem nie kończę już moich identyfikatorów z _t ponieważ jest to zarezerwowane przez standard POSIX.

Zasada o każdym identyfikatorze kończącym się na _t bardzo mnie zaskoczyła. Myślę, że jest to standard POSIX (jeszcze nie jestem pewien) szukający wyjaśnienia i oficjalnego rozdziału i wersetu. To jest z GNU libtool manual , listing nazw zastrzeżonych.

CesarB dostarczył następujący link do POSIX 2004 zarezerwowanych symboli i notatek ' oraz wielu innych zarezerwowanych przedrostków i sufiksów ... można tam znaleźć". Na POSIX 2008 symbole Zastrzeżone są tutaj zdefiniowane. Ograniczenia są nieco bardziej niuansowane niż te powyżej.

 746
Author: 23 revs, 12 users 36%Roger Pate,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-06 12:04:38

Zasady unikania kolizji nazw są zarówno w standardzie C++ (patrz Księga Stroustrupa), jak i wspomniane przez Guru C++ (Sutter itp.).

Reguła osobista

Ponieważ nie chciałem zajmować się sprawami i chciałem prostej zasady, zaprojektowałem osobisty taki, który jest zarówno prosty, jak i poprawny:

Podczas nazywania symbolu unikniesz kolizji z bibliotekami kompilatora / OS / standard, jeśli:

  • nigdy nie zaczynaj symbolu z podkreślenie
  • nigdy nie nazywaj symbolu z dwoma kolejnymi podkreślnikami wewnątrz.

Oczywiście umieszczenie kodu w unikalnej przestrzeni nazw również pomaga uniknąć kolizji (ale nie chroni przed złymi makrami)

Niektóre przykłady

(używam makr, ponieważ są one bardziej zanieczyszczające kod symboli C / C++, ale może to być cokolwiek od nazwy zmiennej do nazwy klasy)

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

Extracts from C++0x draft

Z n3242.plik pdf (oczekuję końcowy standardowy tekst podobny):

17.6.3.3.2 nazwy Globalne [global.nazwy]

Niektóre zestawy nazw i podpisów funkcji są zawsze zarezerwowane dla implementacji:

- każda nazwa, która zawiera podwójny podkreślnik _ _ lub zaczyna się od podkreślnika, po którym następuje wielka litera (2.12), jest zarezerwowana dla implementacji do dowolnego użycia.

- każda nazwa zaczynająca się od podkreślenia jest zarezerwowana dla implementacji do użycia jako nazwa w globalnej przestrzeni nazw.

Ale także:

17.6.3.3.5 user-defined dosłowne sufiksy [usrlit.sufiks]

Dosłowne identyfikatory sufiksów, które nie rozpoczynają się podkreśleniem, są zarezerwowane dla przyszłej standaryzacji.

Ta ostatnia klauzula jest myląca, chyba że uznasz, że nazwa zaczynająca się od podkreślenia i poprzedzona małą literą byłaby w porządku, gdyby Nie zdefiniowano w globalnej przestrzeni nazw...

 172
Author: paercebal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-27 20:32:18

From MSDN :

Użycie dwóch sekwencyjnych znaków podkreślenia ( _ _ ) na początku identyfikatora lub pojedynczego głównego podkreślenia, po którym następuje wielka litera, jest zarezerwowane dla implementacji C++ we wszystkich zakresach. Należy unikać używania jednego głównego podkreślenia, po którym następuje mała litera dla nazw z zakresem plików z powodu ewentualnych konfliktów z obecnymi lub przyszłymi zastrzeżonymi identyfikatorami.

Oznacza to, że można użyć pojedynczego podkreślenia jako prefiks zmiennej członkowskiej, o ile po nim następuje mała litera.

Jest to najwyraźniej zaczerpnięte z sekcji 17.4.3.1.2 standardu C++, ale nie mogę znaleźć oryginalnego źródła dla pełnego standardu online.

Zobacz też to pytanie .

 27
Author: Roger Lipscombe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:50

Jeśli chodzi o drugą część pytania, powszechne jest umieszczanie podkreślenia na końcu nazwy zmiennej, aby nie kolidować z niczym wewnętrznym.

Robię to nawet wewnątrz klas i przestrzeni nazw, ponieważ wtedy muszę zapamiętać tylko jedną regułę(w porównaniu do "na końcu nazwy w zasięgu globalnym, a na początku nazwy wszędzie indziej").

 21
Author: Max Lybbert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-01 16:10:18

Tak, podkreślniki mogą być używane w dowolnym miejscu identyfikatora. Wydaje mi się, że zasady są następujące: dowolne z a-z, a-z, _ w pierwszym znaku i te + 0-9 dla kolejnych znaków.

Prefiksy podkreślenia są powszechne w kodzie C-pojedynczy podkreślnik oznacza "prywatny", a podwójne podkreślenia są zwykle zarezerwowane do użycia przez kompilator.

 2
Author: John Millikin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-23 07:05:58