условный Что делает C ??! ??! оператор?




условный оператор си (4)

??! является trigraph который преобразуется в | , Так говорится:

!ErrorHasOccured() || HandleError();

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

if (ErrorHasOccured())
    HandleError();

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

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

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

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

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

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

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

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


Это trigraph C. ??! это | , так ??!??! является оператором ||


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

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

(Изображение взято из C: A Reference Manual 5th Edition )

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

Поскольку триграфы заменяются во время предварительной обработки, вы можете использовать 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 не предоставил несколько символов, необходимых для языков, отличных от английского, был сделан ряд национальных вариантов, которые заменяли некоторые менее используемые символы с необходимыми .

(акцент мой)

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


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

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

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

{ | } ~ 

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

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

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

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

Телетайп ASR-33

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





trigraphs