Cel sekwencji Trigraph w C ++?

129

Zgodnie z C ++ '03 Standard 2.3 / 1:

Przed jakimkolwiek innym przetwarzaniem każde wystąpienie jednej z następujących sekwencji trzech znaków („sekwencje trygrafów”) zastępuje się pojedynczym znakiem wskazanym w tabeli 1.

----------------------------------------------------------------------------
| trigraph | replacement | trigraph | replacement | trigraph | replacement |
----------------------------------------------------------------------------
| ??=      | #           | ??(      | [           | ??<      | {           |
| ??/      | \           | ??)      | ]           | ??>      | }           |
| ??’      | ˆ           | ??!      | |           | ??-      | ˜           |
----------------------------------------------------------------------------

W prawdziwym życiu oznacza to, że kod printf( "What??!\n" );będzie drukowany, What|ponieważ ??!jest to sekwencja trygrafu, która jest zastępowana |znakiem.

Moje pytanie brzmi: jaki jest cel używania trójgrafów? Czy jest jakaś praktyczna zaleta używania trójgrafów?

UPD : W odpowiedziach wspomniano, że niektóre europejskie klawiatury nie mają wszystkich znaków interpunkcyjnych, więc programiści spoza Stanów Zjednoczonych muszą używać trójgrafów w życiu codziennym?

UPD2 : Visual Studio 2010 ma domyślnie wyłączoną obsługę trygrafów .

Kirill V. Lyadvinsky
źródło
Niektóre znaki interpunkcyjne są trudniejsze do osiągnięcia na europejskich klawiaturach (do tego stopnia, że ​​niektórzy programiści używają układu amerykańskiego do szybszego pisania). Nie widziałem takiego, w którym całkowicie brakuje interpunkcji - może dla języków słowiańskich?
peterchen
2
Może się zdarzyć, że niektóre terminale i / lub wirtualizacja nie pozwalają na łatwy dostęp do niektórych postaci. Z mojego doświadczenia wynika, że ​​głównym winowajcą jest tylda.
Francesco
1
wpisując to na mojej klawiaturze DE-deadkeys, # jest klawiszem obok powrotu, \ to "AltGr" + "ß" (obok 0), ^ to "^" + "^" (z powodu martwych klawiszy; obok 1) , [to „AltGr” + „8”,] to „AltGr” + „9”, | to "AltGr" + "<", {to "AltGr" + "7",} to "AltGr" + "0", a ~ to "~" + "~" (z powodu martwych klawiszy, tuż nad #). więc nic wielkiego. moje palce są jak samodzielne wpisywanie tych kombinacji :-D
nonchip
1
Pomyślałem, że to normalne, że mam dwa układy klawiatury i przełączam je w zależności od pracy, którą wykonuję na komputerze. To powszechny sposób w regionie Europy Środkowej. Używanie tych trygrafów jest dość przerażające. Głosowałbym za usunięciem tego ze standardu.
VX,
1
@VX Masz swoje życzenie!
graham.reeds

Odpowiedzi:

99

Na to pytanie (dotyczące blisko spokrewnionych dwuznaków) można odpowiedzieć.

Sprowadza się to do tego, że zestaw znaków ISO 646 nie zawiera wszystkich znaków składni C, więc są systemy z klawiaturami i wyświetlaczami, które nie radzą sobie ze znakami (chociaż wyobrażam sobie, że są one dość rzadkie dzisiaj).

Ogólnie rzecz biorąc, nie musisz ich używać, ale musisz wiedzieć o nich dokładnie w przypadku napotkanego problemu. Trygrafy są powodem, dla którego ?znak „ ” ma sekwencję ucieczki:

'\?'

Oto kilka sposobów uniknięcia przykładowego problemu:

 printf( "What?\?!\n" ); 

 printf( "What?" "?!\n" ); 

Ale musisz pamiętać, kiedy wpisujesz dwa „?” postaci, o których być może zaczynasz trygraf (iz pewnością nigdy o tym nie myślę).

W praktyce trójgrafy i dwuznaki to coś, o co na co dzień nie martwię się wcale. Ale powinieneś być ich świadomy, ponieważ raz na kilka lat napotkasz związany z nimi błąd (i spędzisz resztę dnia przeklinając ich istnienie). Byłoby miło, gdyby kompilatory mogły być skonfigurowane tak, aby ostrzegały (lub błąd), gdy natrafią na trójgraf lub dwuznak, więc mógłbym wiedzieć, że mam coś, z czym powinienem świadomie się uporać.

Dla kompletności dwuznaki są znacznie mniej niebezpieczne, ponieważ są przetwarzane jako tokeny, więc dwuznak wewnątrz literału ciągu nie zostanie zinterpretowany jako dwuznak.

Aby uzyskać dobrą edukację na temat różnych zabaw z interpunkcją w programach C / C ++ (w tym błędu trygrafu, który z pewnością sprawiłby, że wyrywam sobie włosy), zapoznaj się z artykułem Herba Suttera GOTW # 86 .


Uzupełnienie:

Wygląda na to, że GCC domyślnie nie przetwarza (i będzie ostrzegać) trygrafów. Niektóre inne kompilatory mają opcje wyłączania obsługi trigraph (na przykład IBM). Microsoft zaczął obsługiwać ostrzeżenie (C4837) w VS2008, które musi być jawnie włączone (za pomocą -Wall lub czegoś podobnego).

Michael Burr
źródło
Kompatybilność z C jest jedynym powodem? Czy można je spotkać we współczesnych programach C ++?
Kirill V. Lyadvinsky
Tak, C ++ obsługuje również trygrafy i dwuznaki.
Michael Burr
4
O ile pamiętam, co najmniej jeden używany przeze mnie kompilator (g ++?) Wymaga wyraźnej opcji wiersza poleceń przed przetłumaczeniem trójgrafu i / lub dwuznaku, w przeciwnym razie wyświetlane jest ostrzeżenie, ale nie ma podstawienia.
KTC
1
@ Jla3ep - Osobiście nigdy nie potrzebowałem trygrafów, ale niestety kompilatory będą z nimi przetwarzać kod, więc musisz być ich świadomy (aby uniknąć przypadkowego użycia). Ponadto, jeśli otrzymasz kod z innego miejsca, możesz napotkać jego celowe użycie, ale byłoby to niezwykle niezwykłe. Myślę, że raz na ponad 20 lat napotkałem celowo używane trygrafy (to był jakiś kod dla mainframe IBM).
Michael Burr,
1
To naprawdę działa mi na nerwy tylko wtedy, gdy trygrafy są rozszerzone w komentarzach, aby robić zaskakujące rzeczy.
Joshua,
23

Dzieci dzisiaj! :-)

Tak, sprzęt zagraniczny, taki jak terminal IBM 3270. 3270 nie ma, jeśli dobrze pamiętam, aparatu ortodontycznego! Jeśli chciałeś napisać C na IBM mini / mainframe, to musiał użyć nędzne trójznaków dla każdej granicy bloku. Na szczęście musiałem tylko pisać oprogramowanie w C, aby emulować niektóre funkcje minikomputerów IBM, a nie pisać oprogramowania w C na Systemie / 36.

Spójrz obok klawisza „P”:

klawiatura

Hmmm. Ciężko powiedzieć. Obok „powrotu karetki” znajduje się dodatkowy przycisk, który może być odwrócony: może to była para „[” / „]”, której brakowało. W każdym razie ta klawiatura spowodowałaby żal, gdybyś musiał napisać C.

Ponadto terminale te wyświetlają EBCDIC, „natywny” zestaw znaków mainframe IBM, a nie ASCII (dzięki, Pavel Minaev, za przypomnienie).

Z drugiej strony, jak mówi przewodnik GNU C: „Nie potrzebujesz tego uszkodzenia mózgu”. Kompilator gcc domyślnie wyłącza tę „funkcję”.

Roboprog
źródło
1
Na klawiaturze znajduje się przycisk resetowania. To cudownie! Dziwne, że pierwsza zwróciła moją uwagę.
l46kok
12
Ktokolwiek chce używać C ++ 17 na maszynie EBCDIC, powinien zostać uwięziony za nekrofilię.
SF.
Chyba że platforma nie ma znaków na wszystko inne niż w iso646 może nie wszystko, co można zrobić z trójznaków być wykonywane poprzez wymóg, że każda realizacja definiować albo odwrotny ukośnik lub inny dowolny znak, który nie jest w zestawie C jako znak znak „meta”, zastąpić wszystkie odniesienia do ukośnika odwrotnego w standardzie „meta” i dodać znaki ucieczki odwrotnego ukośnika / meta dla wszystkich elementów zestawu znaków C, które nie są zgodne z ISO-646?
supercat
22

Z The C++ Programming Languagewydania specjalnego, strona 829

Znaki specjalne ASCII [, ], {, }, |, i \zajmują zestaw znaków wyznaczone jako alfabetyczna przez ISO. W większości europejskich krajowych zestawów znaków ISO-646 te pozycje zajmują litery, których nie ma w alfabecie angielskim.

Zestaw trójgrafów umożliwia wyrażanie znaków narodowych w przenośny sposób przy użyciu prawdziwie standardowego minimalnego zestawu znaków. Może to być przydatne do wymiany programów, ale nie ułatwia ludziom czytania programów. Oczywiście długoterminowym rozwiązaniem tego problemu jest, aby programiści C ++ otrzymali sprzęt, który dobrze obsługuje zarówno ich język ojczysty, jak i C ++. Niestety, wydaje się to dla niektórych niewykonalne, a wprowadzenie nowego sprzętu może być frustrująco powolnym procesem.

Obrabować
źródło
8
„Wprowadzenie nowego sprzętu może być frustrująco powolnym procesem”. Szczególnie w porównaniu do szybkiego i bezbolesnego procesu standaryzacji funkcji języka programowania.
jforberg,
4
Jeśli jest to kludge dla układów klawiatury, to zabawne, że nie ma trygrafu np. Do pisania `, czego brakuje we włoskim i kilku innych układach klawiatury
badp
15

Są przeznaczone do użytku w systemach, w których brakuje niektórych znaków z podstawowego zestawu znaków C ++. Nie trzeba dodawać, że takie systemy są niezwykle rzadkie.

CB Bailey
źródło
2
Czy to oznacza, że ​​nigdy nie użyję ich w prawdziwym życiu?
Kirill V. Lyadvinsky
1
W jakim kraju mieszkasz? Nie wszystkie klawiatury dla wszystkich języków mają niezbędne klawisze.
David Thornley,
2
Tak, ale być może będziesz musiał zdawać sobie sprawę z ich istnienia na wypadek, gdyby ktoś spowodował nieoczekiwany wynik, gdy napotkasz, powiedzmy, literał ciągu.
CB Bailey,
4
@David Thornley: Większość nowoczesnych systemów obsługuje wszystkie podstawowe znaki C ++, nawet jeśli nie znajdują się one w konwencjonalnym miejscu lub wymagają sekwencji modyfikatorów do wpisania. Trygrafy musiały być utrzymywane w kodzie źródłowym tylko w systemach, w których znak nie może być faktycznie reprezentowany w systemowym zestawie znaków. Nadal uważam, że takie systemy są niezwykle rzadkie.
CB Bailey,
9

W C ++ 0x zaproponowano usunięcie trygrafów. To powiedziawszy, nadal wydaje się, że istnieją mocne argumenty na ich poparcie - patrz dokument komisji C ++ N2910, który to omawia. Najwyraźniej EBCDIC jest jedną z głównych bastionów, w których są potrzebne.

Pavel Minaev
źródło
Tak, ten „obcy język”! :-)
Roboprog
Tak naprawdę nie mówią zbyt wiele poza „wynikami wewnętrznego badania opinii klientów”, ale cóż. Dziwię się jednak, że EBCDIC jest nadal w powszechnym użyciu (i że te systemy spodziewają się używać kompilatorów C ++ 0x)
peterchen
5

Widziałem trygrafy używane we wczesnych latach 90. do konwersji programów PL / 1 z komputera mainframe w celu uruchomienia / kompilacji / debugowania na komputerze PC.

Bawili się edycją PL / I na komputerze PC za pomocą kompilatora PL / I na C i chcieli, aby kod działał po przeniesieniu z powrotem do komputera mainframe, który nie obsługuje nawiasów klamrowych. Zasugerowałem, że mogą używać makr, takich jak

#def BEGIN {    
#def END }  

lub jako bardziej przyjazną alternatywę PL / I

#def BEGIN ??<
#def END ??>

a jeśli naprawdę chcieli się spodobać, mogli spróbować

#ifdef MAINFRAME
    #def BEGIN ??<
    #def END ??>
#else
    #def BEGIN {    
    #def END }  
#endif

a wtedy program wyglądałby tak, jakby był napisany w języku Pascal. Po prostu dziwnie na mnie patrzyli i nie rozmawiali ze mną przez resztę dnia. Chyba ich nie winię. :)

Tym, co zabiło wysiłek, a nie trójgrafami, były różnice w systemie IO między platformami. Otwieranie plików na komputerze PC różniło się tak bardzo od komputera typu mainframe, że wprowadziłoby zbyt wiele kludge, aby utrzymać ten sam kod działający na obu.

Kelly S. French
źródło
PL / 1 = wersja C IBM (mniej więcej). Zobacz mój komentarz: terminale IBM nie mają kluczy '{' / '}' :-( Trochę trudno napisać C [++] na jednym z nich, w przeciwnym razie.
Roboprog
3

Przede wszystkim dlatego, że standard C wprowadził je w 1989 roku, kiedy pojawiły się problemy z obecnością znaków, które są mapowane na trójgrafach na niektórych komputerach. Do czasu opublikowania standardu C ++ w 1998 r. Zapotrzebowanie na trygrafy nie było duże. Są brodawką na C; są tak samo jak brodawka w C ++. Była taka potrzeba - szczególnie poza anglojęzycznym światem - dlatego dodano je do C.

Jonathan Leffler
źródło
1
Zawsze podejrzewałem, że IBM nie mówi po angielsku :-)
Roboprog
3

Niektóre klawiatury europejskie nie mają (nie miały?) Wszystkich znaków interpunkcyjnych, które miały klawiatury amerykańskie, ponieważ potrzebowały klawiszy do ich niezwykłych znaków alfabetycznych. Na przykład (zmyślając) szwedzka klawiatura miałaby pierścień A w miejscu nawiasu klamrowego.

Aby dostosować się do tych użytkowników, trygrafy są sposobem wprowadzania znaków interpunkcyjnych przy użyciu tylko najpopularniejszych znaków ASCII.

Ned Batchelder
źródło
4
Trygrafy tak naprawdę nie dotyczą wprowadzania danych (powodują, że kod jest dość nieczytelny), są raczej systemami, które w rzeczywistości nie mają wymaganych znaków. Jeśli system może rejestrować i wyświetlać znak - nawet jeśli trzeba wpisać sekwencję klawiszy podobną do trygrafu - znacznie łatwiej byłoby nie zachować sekwencji trygrafu w źródle.
CB Bailey,
2

Są tam głównie z powodów historycznych. Obecnie większość nowoczesnych klawiatur dla większości języków umożliwia dostęp do wszystkich tych znaków, ale kiedyś był to problem z niektórymi klawiaturami europejskimi. Dlatego wymyślono trójgrafy.

Jeśli nie wiesz, do czego służą, nie powinieneś ich używać.

Jednak nadal dobrze jest być ich świadomym, ponieważ możesz przypadkowo i nieumyślnie użyć go w swoim kodzie.

sbi
źródło