Dlaczego ludzie tak często używają __ (podwójne podkreślenie) w C ++

93

Rzuciłem okiem na kod C ++ open source i zauważyłem wiele podwójnych punktów pod punktami, które są używane w kodzie, głównie na początku nazw zmiennych.

return __CYGWIN__;

Zastanawiam się tylko, czy jest tego powód, czy tylko niektórzy ludzie kodują style? Myślę, że utrudniam czytanie.

Nathan W.
źródło
2
Dlaczego trudne do odczytania? Został zaprojektowany głównie jako ogranicznik, podobnie jak cytaty. O ile pamiętam, jest używany głównie do wbudowanych stałych.
Matthew Scharley
1
Nie, to nie jest ogranicznik. Podkreślenia służą do odróżnienia nazw zarezerwowanych dla implementacji od nazw, których może używać kod źródłowy użytkowników. Użytkownicy mogą to robić, #define FOO 1ale nie mogą, #define __FOO__ 1dlatego implementacja może swobodnie używać nazwy __FOO__dla własnych makr, zmiennych, funkcji itp.
Jonathan Wakely,
Myślę, że Matthew miał na myśli, że stylistycznie / wizualnie jest to ogranicznik, a nie funkcjonalny. Co jest ciekawą hipotezą, ale niepoprawną, biorąc pod uwagę to, co przeczytałem wcześniej i odpowiedź Jonathana.
JMI MADISON

Odpowiedzi:

128

Od programowania w C ++, reguł i zaleceń :

Użycie dwóch podkreślników („__”) w identyfikatorach jest zarezerwowane do użytku wewnętrznego kompilatora zgodnie ze standardem ANSI-C.

Podkreślenia („_”) są często używane w nazwach funkcji bibliotecznych (takich jak „_main” i „_exit”). Aby uniknąć kolizji, nie zaczynaj identyfikatora od podkreślenia.

maccullt
źródło
1
Ten przewodnik wygląda tak, jakby został napisany przed namespacewprowadzeniem.
cz
pochodziło również z Imperial College London, a nie ze standardu C ++; to może być dobra sugestia.
stucash
1
@cz Przestrzenie nazw są nieistotne. Nagłówek systemowy mógłby definiować nazwę makra zaczynającą się od podkreślenia, np _main.
martinkunev
50

O ile nie czują, że są „częścią implementacji”, czyli standardowymi bibliotekami, to nie powinni.

Zasady są dość szczegółowe i nieco bardziej szczegółowe niż sugerowały to niektóre inne.

Wszystkie identyfikatory, które zawierają podwójne podkreślenie lub rozpoczynają się od podkreślenia, po którym następuje duża litera, są zarezerwowane do użytku implementacji we wszystkich zakresach, tj. Mogą być używane dla makr.

Ponadto wszystkie inne identyfikatory zaczynające się od podkreślenia (tj. Po którym nie następuje inny podkreślenie ani duża litera) są zarezerwowane do implementacji w zakresie globalnym. Oznacza to, że możesz używać tych identyfikatorów we własnych przestrzeniach nazw lub w definicjach klas.

Dlatego firma Microsoft używa nazw funkcji z początkowym podkreśleniem i małymi literami w wielu podstawowych funkcjach biblioteki wykonawczej, które nie są częścią standardu C ++. Te nazwy funkcji na pewno nie kolidują ze standardowymi funkcjami C ++ ani funkcjami kodu użytkownika.

CB Bailey
źródło
1
W C ++ widzę tylko [lex.name] i nazwy globalne [global.names]. Czy możesz podać referencje? dzięki
a.lasram
36

Zgodnie ze standardem C ++ identyfikatory zaczynające się od jednego podkreślenia są zarezerwowane dla bibliotek. Identyfikatory zaczynające się od dwóch podkreśleń są zarezerwowane dla dostawców kompilatorów.

James Curran
źródło
18
Co więcej: identyfikatory zawierające w dowolnym miejscu podwójne podkreślenie są zarezerwowane. 17.4.3.1.2
Steve Jessop
W C ++ widzę tylko [lex.name] i nazwy globalne [global.names]. Czy możesz podać referencje? dzięki
a.lasram
10

Powyższe uwagi są prawidłowe. __Symbol__jest generalnie magicznym tokenem dostarczanym przez dostawcę pomocnego kompilatora (lub preprocesora). Prawdopodobnie najczęściej używanymi z nich są __FILE__i __LINE__, które są rozszerzane przez preprocesor C w celu wskazania bieżącej nazwy pliku i numeru wiersza. Jest to przydatne, gdy chcesz zarejestrować jakiś rodzaj błędu potwierdzenia programu, w tym tekstową lokalizację błędu.

bagno
źródło
8

To coś, czego nie powinieneś robić w „normalnym” kodzie. Gwarantuje to, że kompilatory i biblioteki systemowe mogą definiować symbole, które nie będą kolidować z Twoimi.

Menkboy
źródło
4

Podwójne podkreślenia są zastrzeżone dla implementacji

Najczęściej głosowana odpowiedź cytuje Programowanie w C ++: Zasady i zalecenia :

„Użycie dwóch znaków podkreślenia („ __ ”) w identyfikatorach jest zarezerwowane do użytku wewnętrznego kompilatora zgodnie ze standardem ANSI-C”.

Jednak po przeczytaniu kilku standardów C ++ i C nie mogłem znaleźć żadnej wzmianki o podkreśleniach ograniczonych tylko do wewnętrznego użytku kompilatora. Standardy są bardziej ogólne i zastrzegają podwójne podkreślenia do wdrożenia .

C ++

C ++ (bieżąca wersja robocza, dostęp 2019-5-26) stwierdza w lex.name:

  • Każdy identyfikator, który zawiera podwójne podkreślenie __ lub zaczyna się od podkreślenia, po którym następuje duża litera, jest zarezerwowany dla implementacji do dowolnego użytku.
  • Każdy identyfikator, który zaczyna się od podkreślenia, jest zarezerwowany dla implementacji i może być używany jako nazwa w globalnej przestrzeni nazw.

do

Chociaż to pytanie jest specyficzne dla C ++, zacytowałem odpowiednie sekcje ze standardów C 99 i 17:

C99 sekcja 7.1.3

  • 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życia jako identyfikatory z zakresem pliku zarówno w przestrzeni nazw zwykłych, jak i nazw znaczników.

C17 mówi to samo co C99.

Jaka jest implementacja ?

W przypadku C / C ++ implementacja luźno odnosi się do zestawu zasobów niezbędnych do utworzenia pliku wykonywalnego z plików źródłowych użytkownika. To zawiera:

  • preprocesor
  • kompilator
  • konsolidator
  • biblioteka standardowa

Przykładowe realizacje

Istnieje wiele różnych implementacji C ++ wymienionych w Wikipedii . (bez linku do kotwicy, ctrl + f "implementacja")

Oto przykład implementacji C / C ++ firmy Digital Mars, która rezerwuje pewne słowa kluczowe dla ich funkcji.

Niezwykły Bucket
źródło
3

Oprócz bibliotek, na które odpowiadało wiele innych osób, niektórzy ludzie nazywają również makra lub #define wartości do użycia z preprocesorem. Ułatwiłoby to pracę i mogłoby umożliwić obejście błędów w starszych kompilatorach.

Podobnie jak inni wspomnieli, pomaga zapobiegać kolizji nazw i pomaga odróżnić zmienne biblioteczne od własnych.

Sqeaky
źródło