Что делает C??!??! оператор?

Я видел строку C, которая выглядела так:

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

Он правильно скомпилирован и, кажется, работает нормально. Кажется, что он проверяет, произошла ли ошибка, и если она есть, она обрабатывает ее. Но я не совсем уверен, что он на самом деле делает или как он это делает. Это похоже на то, что программист пытается выразить свои чувства по поводу ошибок.

Я никогда не видел ??!??! раньше на любом языке программирования, и я нигде не могу найти документацию. (Google не помогает с поисковыми запросами типа ??!??!). Что он делает и как работает образец кода?

Ответ 1

??! является trigraph, который переводится в |. Поэтому он говорит:

!ErrorHasOccured() || HandleError();

который из-за короткого замыкания эквивалентен:

if (ErrorHasOccured())
    HandleError();

Гуру недели (имеет дело с С++, но актуальным здесь), где я взял это.

Возможное происхождение триграфов или как @DwB указывает на комментарии, которые, скорее всего, из-за сложности EBCDIC (опять же). Эта дискуссия на панели разработчиков developerWorks, похоже, поддерживает эту теорию.

Из ISO/IEC 9899: 1999 §5.2.1.1, сноска 12 (h/t @Random832):

Триграфные последовательности позволяют вводить символы, которые не определены в Инвариантном коде, как описанный в ISO/IEC 646, который является подмножеством семибитового кода USSCII.

Ответ 2

Хорошо, почему это вообще существует, вероятно, отличается от того, почему оно существует в вашем примере.

Все началось полвека назад с перепродажи печатных терминалов связи в качестве пользовательских интерфейсов пользователя. В начальный период Unix и C, который был Teletype ASR-33.

Это устройство было медленным (10 cps), шумным и уродливым, и его вид набора символов ASCII закончился 0x5f, поэтому он (внимательно посмотрите на рис.) ни один из клавиш:

{ | } ~ 

Триграфы были определены для устранения конкретной проблемы. Идея заключалась в том, что C-программы могут использовать подмножество ASCII, найденное на ASR-33, и в других средах, не имеющих высоких значений ASCII.

Ваш пример на самом деле два из ??!, каждый из которых означает |, поэтому результат ||.

Однако люди, пишущие код C почти по определению, имели современное оборудование, 1 поэтому я предполагаю, что кто-то демонстрирует или развлекает себя, оставляя в коде код своего пасхального яйца.

Это наверняка сработало, это привело к чрезвычайно популярному вопросу SO.

Телевидение ASR-33

                                                                SUP > 1. В этом отношении триграфы были изобретены комитетом ANSI, который впервые встретился после того, как C стал безудержным успехом, поэтому ни один из исходных кодов C или кодеров не использовал бы их.

Ответ 3

Это c trigraph. ??! |, поэтому ??!??! - оператор ||

Ответ 4

Как уже говорилось, ??!??! представляет собой по существу два триграммы (??! и ??! снова) которые заменяются - переводятся на ||, т.е. Логическое ИЛИ, препроцессором.

Следующее изображение, содержащее все триграфы, должно помочь устранить неоднозначные комбинации альтернативных триграмм:

введите описание изображения здесь (Изображение взято из C: Справочное руководство 5-го издания)

Итак, триграф, который выглядит как ??(??), в конечном итоге будет отображаться на [], ??(??)??(??) будет заменен на [][] и т.д., вы получите эту идею.

Поскольку триграфы заменяются во время предварительной обработки, вы можете использовать cpp, чтобы получить представление о выходе самостоятельно, используя глупую программу trigr.c

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

и обрабатывая его с помощью

cpp -trigraphs trigr.c 

Вы получите консольный вывод

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

Как вы можете заметить, необходимо указать опцию -trigraphs, иначе cpp выдаст предупреждение; это указывает на то, как триграфы ушли в прошлое и не имеют современной ценности, кроме путаницы людей, которые могут столкнуться с ними.


Что касается обоснования введения триграфов, то это лучше понять при просмотре раздела истории ISO/IEC 646:

ISO/IEC 646 и его предшественник ASCII (ANSI X3.4) в значительной степени одобрили существующую практику кодирования символов в телекоммуникационной отрасли.

Поскольку ASCII не предоставил несколько символов, необходимых для языков, отличных от английского, было сделано несколько национальных вариантов, которые заменяли некоторые менее используемые символы с необходимыми.

(акцент мой)

Итак, по сути, некоторые необходимые персонажи (те, для которых существует триграф) были заменены в некоторых национальных вариантах. Это приводит к альтернативному представлению с использованием триграфов, состоящих из символов, которые все еще имели другие варианты.