Jakie są zasady dotyczące używania podkreślenia w identyfikatorze C ++?
W C ++ powszechne jest nazywanie zmiennych składowych za pomocą pewnego rodzaju przedrostka oznaczającego fakt, że są one zmiennymi składowymi, a nie zmiennymi lokalnymi lub parametrami. Jeśli pochodzisz z tła MFC, prawdopodobnie użyjesz m_foo
. Widziałem też myFoo
sporadycznie.
Wydaje się, że C # (lub po prostu .NET) zaleca używanie tylko podkreślenia, jak w _foo
. Czy jest to dozwolone przez standard C ++?
Odpowiedzi
Zasady (które nie uległy zmianie w C ++ 11):
- Zarezerwowane w dowolnym zakresie, w tym do użytku jako makra implementacyjne :
- identyfikatory zaczynające się od podkreślenia, po którym bezpośrednio następuje duża litera
- identyfikatory zawierające sąsiadujące podkreślenia (lub „podwójne podkreślenie”)
- Zarezerwowane w globalnej przestrzeni nazw:
- identyfikatory zaczynające się od podkreślenia
- Ponadto wszystko w
std
przestrzeni nazw jest zarezerwowane. (Możesz jednak dodawać specjalizacje szablonów).
Ze standardu C ++ 2003:
17.4.3.1.2 Nazwy globalne [lib.global.names]
Pewne zestawy nazw i sygnatur funkcji są zawsze zastrzeżone dla implementacji:
- Każda nazwa, która zawiera podwójne podkreślenie (
__
) lub zaczyna się od podkreślenia, po którym następuje duża litera (2.11), jest zastrzeżona dla implementacji do dowolnego użytku.- Każda nazwa, która zaczyna się od podkreślenia, jest zarezerwowana dla implementacji i może być używana 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), a C99 jest odniesieniem normatywnym (1.2 / 1, C ++ 03), mają one również zastosowanie, ze standardu C z 1999:
7.1.3 Zarezerwowane identyfikatory
Każdy nagłówek deklaruje lub definiuje wszystkie identyfikatory wymienione w skojarzonej z nim podrozdziale i opcjonalnie deklaruje lub definiuje identyfikatory wymienione w powiązanych z nim przyszłych podrozdziałach kierunków bibliotecznych oraz identyfikatory, które są zawsze zarezerwowane do dowolnego użytku lub do użycia jako identyfikatory zakresu zbioru.
- Wszystkie identyfikatory zaczynające się od podkreślenia i dużej litery lub innego podkreślenia są zawsze zarezerwowane do dowolnego użytku.
- Wszystkie identyfikatory zaczynające się od podkreślenia są zawsze zarezerwowane do użytku jako identyfikatory z zakresem pliku zarówno w przestrzeni nazw zwykłych, jak i nazw znaczników.
- Każda nazwa makra w którymkolwiek z poniższych podrozdziałów (łącznie z przyszłymi wskazówkami dotyczącymi biblioteki) jest zarezerwowana do użytku w sposób określony, jeśli uwzględniono którykolwiek z powiązanych z nią nagłówków; chyba że wyraźnie określono inaczej (patrz 7.1.4).
- Wszystkie identyfikatory z powiązaniami zewnętrznymi w którymkolwiek z poniższych podrozdziałów (łącznie z przyszłymi wskazówkami dotyczącymi biblioteki) są zawsze zarezerwowane do użytku jako identyfikatory z powiązaniami zewnętrznymi. 154
- Każdy identyfikator z zakresem pliku wymienionym w którymkolwiek z poniższych podrozdziałów (w tym przyszłe wskazówki dotyczące biblioteki) jest zarezerwowany do użytku jako nazwa makra i jako identyfikator z zakresem pliku w tej samej przestrzeni nazw, jeśli uwzględniono którykolwiek z powiązanych z nim nagłówków.
Żadne inne identyfikatory nie są zarezerwowane. Jeśli program deklaruje lub definiuje identyfikator w kontekście, w którym jest on zarezerwowany (inny niż dozwolony w 7.1.4), lub definiuje zarezerwowany identyfikator jako nazwę makra, zachowanie jest niezdefiniowane.
Jeśli program usunie (wraz z
#undef
) jakąkolwiek definicją makra identyfikatora z pierwszej grupy wymienionej powyżej, zachowanie jest niezdefiniowane.154) Lista zarezerwowanych identyfikatorów z zewnętrznym wiązaniem obejmuje
errno
,math_errhandling
,setjmp
, iva_end
.
Mogą obowiązywać inne ograniczenia. Na przykład standard POSIX rezerwuje wiele identyfikatorów, które prawdopodobnie pojawią się w normalnym kodzie:
- Nazwy zaczynające się od dużej
E
litery, po której następuje cyfra lub wielka litera:- mogą być używane dla dodatkowych nazw kodów błędów.
- Nazwy zaczynające się od małej litery
is
lubto
zakończone małą literą- może być używany do dodatkowego testowania znaków i funkcji konwersji.
- Nazwy zaczynające się od,
LC_
po których następuje duża litera- może być używany do dodatkowych makr określających atrybuty ustawień regionalnych.
- Nazwy wszystkich istniejących funkcji matematycznych z przyrostkiem
f
lubl
są zastrzeżone- dla odpowiednich funkcji, które działają odpowiednio na argumentach zmiennoprzecinkowych i długich podwójnych argumentach.
- Nazwy zaczynające się od,
SIG
po których następuje duża litera, są zastrzeżone- dodatkowe nazwy sygnałów.
- Nazwy zaczynające się od,
SIG_
po których następuje duża litera, są zastrzeżone- dla dodatkowych działań sygnalizacyjnych.
- Nazwiska zaczynające się
str
,mem
czywcs
następuje listem małymi zastrzeżone- dla dodatkowych funkcji ciągów i tablic.
- Nazwiska zaczynające się
PRI
lubSCN
następuje każdej litery małymi lubX
są zastrzeżone- dla dodatkowych makr specyfikatorów formatu
- Nazwy kończące się na
_t
są zastrzeżone- dodatkowe nazwy typów.
Chociaż używanie tych nazw do własnych celów w tej chwili może nie powodować problemu, to jednak stwarzają 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 reguły: nie używaj nigdzie podwójnych podkreśleń, co jest łatwe, ponieważ rzadko używam podkreślenia.
Po zbadaniu tego artykułu nie kończę już moich identyfikatorów, _t
ponieważ jest to zastrzeżone przez standard POSIX.
Zasada dotycząca dowolnego identyfikatora kończącego się na _t
bardzo mnie zaskoczyła. Myślę, że to standard POSIX (jeszcze nie jestem pewien) szukający wyjaśnień oraz oficjalnego rozdziału i wersetu. To pochodzi z podręcznika GNU libtool , zawierającego nazwy zastrzeżone.
CesarB podał poniższy link do zastrzeżonych symboli POSIX 2004 i zauważa, że „można tam znaleźć wiele innych zastrzeżonych przedrostków i przyrostków ...”. W POSIX 2008 zastrzeżone symbole zdefiniowane są tutaj. Ograniczenia są nieco bardziej zniuansowane niż powyższe.
Zasady unikania kolizji nazw są zarówno w standardzie C ++ (patrz książka Stroustrupa), jak i wspomniane przez guru C ++ (Sutter itp.).
Zasada osobista
Ponieważ nie chciałem zajmować się przypadkami i chciałem prostej zasady, zaprojektowałem osobistą, która jest zarówno prosta, jak i poprawna:
Nazywając symbol, unikniesz kolizji z bibliotekami kompilatora / systemu operacyjnego / standardu, jeśli:
- nigdy nie zaczynaj symbolu od podkreślenia
- nigdy nie nazywaj symbolu z dwoma kolejnymi podkreśleniami w środku.
Oczywiście umieszczenie kodu w unikalnej przestrzeni nazw pomaga również uniknąć kolizji (ale nie chroni przed złymi makrami)
Kilka przykładów
(Używam makr, ponieważ są one bardziej zanieczyszczające kod symboli C / C ++, ale może to być wszystko, od nazwy zmiennej do nazwy klasy)
#define _WRONG
#define __WRONG_AGAIN
#define RIGHT_
#define WRONG__WRONG
#define RIGHT_RIGHT
#define RIGHT_x_RIGHT
Wyciągi z wersji roboczej C ++ 0x
Z pliku n3242.pdf (oczekuję, że ostateczny standardowy tekst będzie podobny):
17.6.3.3.2 Nazwy globalne [global.names]
Pewne zestawy nazw i sygnatur funkcji są zawsze zastrzeżone dla implementacji:
- Każda nazwa, która zawiera podwójne podkreślenie _ _ lub zaczyna się od podkreślenia, po którym następuje duża litera (2.12), jest zastrzeżona dla implementacji do dowolnego użytku.
- Każda nazwa, która zaczyna się od podkreślenia, jest zarezerwowana dla implementacji do użycia jako nazwa w globalnej przestrzeni nazw.
Ale również:
17.6.3.3.5 Zdefiniowane przez użytkownika sufiksy literałów [usrlit.suffix]
Literalne identyfikatory sufiksów, które nie zaczynają się od podkreślenia, są zarezerwowane dla przyszłej standaryzacji.
Ta ostatnia klauzula jest myląca, chyba że uznasz, że nazwa zaczynająca się od jednego podkreślenia i zakończona małą literą byłaby OK, gdyby nie została zdefiniowana w globalnej przestrzeni nazw ...
Z MSDN :
Użycie dwóch kolejnych znaków podkreślenia (__) na początku identyfikatora lub pojedynczego początkowego podkreślenia, po którym następuje duża litera, jest zarezerwowane dla implementacji C ++ we wszystkich zakresach. Należy unikać używania jednego wiodącego podkreślenia, po którym następuje mała litera w nazwach z zakresem pliku, ze względu na możliwe konflikty z obecnymi lub przyszłymi zastrzeżonymi identyfikatorami.
Oznacza to, że możesz użyć pojedynczego podkreślenia jako przedrostka zmiennej składowej, o ile występuje po nim mała litera.
Najwyraźniej pochodzi to z sekcji 17.4.3.1.2 standardu C ++, ale nie mogę znaleźć oryginalnego źródła pełnego standardu w Internecie.
Zobacz także to pytanie .
Jeśli chodzi o drugą część pytania, często umieszcza się podkreślenie na końcu nazwy zmiennej, aby nie kolidować z niczym wewnętrznym.
Robię to nawet w klasach i przestrzeniach nazw, ponieważ wtedy muszę zapamiętać tylko jedną regułę (w porównaniu do „na końcu nazwy w zasięgu globalnym i początku nazwy wszędzie indziej”).
Tak, podkreślenia mogą być używane w dowolnym miejscu identyfikatora. Uważam, że zasady są następujące: dowolne z az, AZ, _ w pierwszym znaku i te + 0-9 dla kolejnych znaków.
Przedrostki podkreślenia są powszechne w kodzie C - pojedynczy znak podkreślenia oznacza „prywatny”, a podwójne podkreślenie jest zwykle zarezerwowane do użytku przez kompilator.