Co robi C! operator?

Widziałem linię C, która wyglądała tak:

!ErrorHasOccured() ??!??! HandleError();

Skompilowany poprawnie i wydaje się działać ok. Wygląda na to, że sprawdza, czy wystąpił błąd, a jeśli wystąpił, obsługuje go. Ale nie jestem pewien, co to właściwie robi, ani Jak to robi. Wygląda na to, że programista próbuje wyrazić swoje uczucia dotyczące błędów.

Nigdy wcześniej nie widziałem ??!??! w żadnym języku programowania i nigdzie nie mogę znaleźć dla niego dokumentacji. (Google nie pomaga w wyszukiwane hasła jak ??!??!). Co to robi i jak działa próbka kodu?

Author: Nathaniel Ford, 2011-10-19

4 answers

??! jest trygrafem , który tłumaczy się na |. Tak jest napisane:

!ErrorHasOccured() || HandleError();

Które ze względu na zwarcie jest równoważne:

if (ErrorHasOccured())
    HandleError();

Guru Tygodnia (zajmuje się C++ , ale istotne tutaj), gdzie podniosłem to.

Możliwe pochodzenie trygrafów lub jak wskazuje @DwB w komentarzach, jest bardziej prawdopodobne ze względu na trudności EBCDIC (ponownie). Ta dyskusja na forum IBM developerworks zdaje się popierać tę teorię.

Od ISO / IEC 9899: 1999 §5.2.1.1, przypis 12 (h/t @Random832):

Sekwencje trygrafu umożliwiają wprowadzanie znaków, które nie są zdefiniowane w kodzie Niezmienniczym jako opisany w ISO / IEC 646, który jest podzbiorem siedmiobitowego zestawu kodów ASCII.

 1341
Author: user786653,
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
2012-03-21 08:52:52

Cóż, dlaczego to istnieje w ogóle jest prawdopodobnie inne niż dlaczego istnieje w twoim przykładzie.

Wszystko zaczęło się pół wieku temu od zmiany przeznaczenia terminali komunikacyjnych w formie papierowej jako interfejsów użytkownika komputera. W początkowej erze Unix i C był to Teletype ASR-33.

To urządzenie było powolne (10 cps), hałaśliwe i brzydkie, a jego widok zestawu znaków ASCII kończył się na 0x5f, więc nie miało (przyjrzyj się uważnie obrazkowi) żadnego z klawiszy:

{ | } ~ 

Trygrafy zostały zdefiniowane w celu rozwiązania konkretnego problemu. Pomysł polegał na tym, że programy C mogą używać podzbioru ASCII znalezionego na ASR-33 i w innych środowiskach, w których brakuje wysokich wartości ASCII.

Twój przykład to właściwie dwa z ??!, każdy oznacza |, więc wynikiem jest ||.

Jednak ludzie piszący kod C niemal z definicji mieli nowoczesny sprzęt,1 więc zgaduję: ktoś się popisuje lub bawi, zostawiając Rodzaj pisanki w kod do znalezienia. To na pewno zadziałało, doprowadziło do szalenie popularnego pytania.

Teletype ASR-33

ASR-33 Teletype


1. W związku z tym, trygrafy zostały wynalezione przez Komitet ANSI, który po raz pierwszy spotkał się z Po C stał się uciekającym sukcesem, więc żaden z oryginalnego kodu C ani programiści nie użyliby ich.
 362
Author: DigitalRoss,
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
2016-08-15 18:02:28

To C trygraf . ??! jest |, Więc ??!??! jest operatorem ||

 143
Author: Joel Falcou,
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-03-08 22:15:38

Jak już wspomniano {[3] } jest zasadniczo dwa trygrafy (??! i ??! Ponownie), które zostają zastąpione-przetłumaczone na ||, czyli logiczne lub, przez preprocesor.

Poniższy obraz zawierający wszystkie trygrafy powinien pomóc w rozróżnieniu alternatywnych kombinacji trygrafu:

Tutaj wpisz opis obrazka (zdjęcie zaczerpnięte z C: A Reference Manual 5th Edition)

Więc trygraf wygląda na to, że ??(??) W końcu mapuje się do [], ??(??)??(??) zostanie zastąpiony przez [][] i tak dalej, masz pomysł.

Ponieważ trygrafy są zastępowane podczas wstępnego przetwarzania, możesz użyć cpp aby uzyskać widok wyjścia, użyj głupiego programu trigr.c:

void main(){ const char *s = "??!??!"; } 

I przetwarzanie go za pomocą:

cpp -trigraphs trigr.c 

Otrzymasz wyjście konsoli

void main(){ const char *s = "||"; }

Jak można zauważyć, opcja -trigraphs musi być określona, inaczej cpp wystawi ostrzeżenie; to wskazuje na to, że trigrafy należą do przeszłości i nie mają żadnej nowoczesnej wartości poza myleniem ludzi, którzy mogą na nie wpaść.


Jeśli chodzi o uzasadnienie wprowadzenia trygrafów, lepiej jest to zrozumieć patrząc na sekcję Historia ISO/IEC 646:

ISO / IEC 646 i jego poprzednik ASCII (ANSI X3. 4) w dużej mierze potwierdziły istniejącą praktykę dotyczącą kodowania znaków w branży telekomunikacyjnej.

ponieważ ASCII nie dostarczyło wielu znaków potrzebnych do języków innych niż Angielski, stworzono wiele wariantów narodowych, które zastąpiły mniej używane znaki potrzebnymi.

(moje)

Tak więc, w istocie, niektóre potrzebne Znaki (te, dla których istnieje trygraf) zostały zastąpione w niektórych wariantach narodowych. Prowadzi to do alternatywnej reprezentacji za pomocą trygrafów składających się ze znaków, które Inne warianty miały jeszcze ok.

 88
Author: Jim Fasarakis Hilliard,
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-08-18 23:49:19