Що означає ??! ?? оператор робити на C?


1990

Я побачив рядок C, який виглядав так:

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

Вона складена правильно і, здається, працює нормально. Схоже, це перевірка, чи виникла помилка, і якщо вона є, вона обробляє її. Але я не дуже впевнений, що це насправді чи як це робить. Схоже, програміст намагається висловити свої почуття щодо помилок.

Я ніколи раніше не бачив ??!??!жодної мови програмування, і ніде не можу знайти документацію для цього. (Google не допомагає з такими термінами пошуку ??!??!). Що це робить і як працює зразок коду?


44
@PeterOlson, як ви очікуєте !ErrorHasOccurred() ??!???! HandleError();компілювати? Ось так ??! ??? !. Доводить суть?
CVn

31
Я пропоную вам прочитати чистий код. ErrorHasOcured () має бути відновлений до ErrorHasNotOcured (), таким чином очищаючи знак оклику ... хто встигає зрозуміти всіх цих операторів ??!
КадекМ

17
Я радше віддаю перевагу ErrorHasOccured() && HandleError()собі. Ось так це робить і Луа.
Hugo Zink

76
@KadekM, переміщення заперечення у назві функції не означає чистого коду, а навпаки.
marcelm

14
Примітка для всіх, хто опинився тут після боротьби на смерть зі своєю пошуковою системою: SymbolHound може допомогти у символічних пошуках.
Якоб

Відповіді:


1579

??!- триграф, що перекладається на |. Так сказано:

!ErrorHasOccured() || HandleError();

який через коротке замикання еквівалентний:

if (ErrorHasOccured())
    HandleError();

Гуру тижня (стосується C ++, але тут актуально), де я підбирав це.

Можливе походження триграфів або як зазначає @DwB у коментарях, це швидше через те, що EBCDIC буде важко (знову). Ця дискусія на борту розробників IBM підтримує цю теорію.

З ISO / IEC 9899: 1999 §5.2.1.1, виноска 12 (год / т @ Random832):

Послідовності триграфа дозволяють вводити символи, які не визначені в наборі інваріантного коду, як описано в ISO / IEC 646, який є підмножиною семи бітного набору коду ASCII США.


377
Спочатку триграфи були потрібні у випадку, якщо у вас на клавіатурі не було, наприклад, "|" символ. Тут або програміст навмисно дратує, або якась химерна редакторська функція
Мартін Бекетт

36
Так, це рівнозначно if (ErrorHasOccured()) HandleError(). На щастя, ви зазвичай стикаєтеся з цією ідіомою лише в коді perl.
користувач786653

22
Це не обов'язково EBCDIC - набір символів, для якого потрібні триграфі, майже точно відповідає набору символів, які не є інваріантними в ISO-646 (тобто старі "національні стандарти ascii").
Випадково832

52
Ідеально читаною альтернативою буде, ErrorHasOccurred() && HandleError();тобто якщо ви звикли до сценаріїв оболонок. :)
Ям Маркович

18
Прочитайте це як "Або немає помилкиHasOcurred, або ви повинні HandleError", @SparkyRobinson.
Омар Антолін-Камарена

453

Ну чому це взагалі існує, мабуть, відрізняється від того, чому воно існує у вашому прикладі.

Все почалося півстоліття тому із заміни терміналів зв'язку на твердій копії як інтерфейсу користувача комп'ютера. У початкові епохи Unix і C це був телевізор ASR-33.

Цей пристрій був повільним (10 кадрів в секунду) і галасливим і некрасивим, а його набір символів ASCII закінчувався на рівні 0x5f, тому в ньому (уважно подивіться на малюнок) жодна з клавіш:

{ | } ~ 

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

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

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

Це впевнено спрацювало, це призвело до надзвичайно популярного питання SO.

Телевізор ASR-33

                                            Телевізор ASR-33


1. З цього приводу триграфи були винайдені комітетом ANSI, який вперше зібрався після того, як C набув успіху, тому жоден з оригінальних кодів C або кодерів не використовував би їх.


18
Це не єдиний випадок відсутніх символів на клавіатурі та наборі символів. Commodore 64, ймовірно, буде більш знайомим багатьом людям у віці тридцяти і вище - відображений символ встановлює як браковані дужки (і, мабуть, також смугу та нахил) - у цьому випадку тому, що "ASCII" не був ASCII . У ECMA-6 (майже завжди його називають ASCII, але не США-ASCII) було 18 кодових регіонів, але я не знаю, які вони були. Єдине, що я можу сказати точно - в британському "ASCII" #замінили £. В інших регіонах, можливо, "ASCII" не мав дужок і т.д.
Steve314

7
Аналогічного набору символів ATASCII для 8-бітних комп'ютерів Atari також не вистачало {}, а також ~ і `.
dan04

42
Дивіться ці дві статті у Вікіпедії. Мені вже достатньо років, щоб все ще пам’ятати епоху 7-бітових національних візиток (хоча я впевнений, що вони все ще затримуються в деяких темних незабруднених куточках), і книга, з якої я вперше дізналася С, вважала за потрібне попередити про можливість if (x || y) { a[i] = '\0'; }виглядати як if (x öö y) ä aÄiÅ = 'Ö0'; åу неправильній шафі.
Ільмарі Каронен

9
Ще одна цікава історична примітка полягає в тому, що Unix (яка була великою платформою C, на якій він працював), можливо, була першою системою будь-якого значення (і, можливо, першою загальною) за замовчуванням алфавітних значень у нижньому регістрі, а не у верхньому регістрі. Хоча я не бачив на власні очі багатьох сучасних систем, я думаю, що це було справжнім знаком витонченості. Окрім того, що справді є єдиною гідною ОС, Unix також перетворила ваш верхній регістр на нижній, а не навпаки. Ці хлопці були дійсно круті.
DigitalRoss

16
Смішна історія, яку я повинен вам розповісти ... компілятор XL Fortran робочої станції IBM RS / 6000 був розроблений з компілятора XL C. У перших кількох випусках вони випадково пішли в обробку триграфа, тому з'явилися легальні послідовності символів Фортран (у прямому рядку, IIRC), які неправильно трактувались як C триграфи, що призводить до цікавих помилок!
Філ Перрі

166

Це C тріграф . ??!є |, так ??!??!і оператор||


5
Триграф походить з періоду, коли деякі клавіатури не мали всіх клавіш, які вони мають зараз. Він також допомагає, коли деякий текстовий редактор зарезервував спеціальні символи для спеціальних речей. Це здебільшого пережиток минулого та
уможливлення вікторини

5
Тому що, мабуть, деякі клавіатури не мають "|" тож у деяких людей немає нічого іншого, крім як клацати голову клавіатурою кілька разів, поки не з’явиться триграф, який надасть їм потрібні символи.
Сова

І тут є <iso646.h>заголовок-файл.
David R

149

Як вже говорилося ??!??!, по суті , два тріграфи ( ??!і ??!знову) mushed разом , які замінюються переведений на ||, тобто логічне АБО , препроцесором.

Наступна таблиця, що містить кожен триграф, повинна допомогти розмежувати альтернативні комбінації триграфа:

Trigraph   Replaces

??(        [
??)        ]
??<        {
??>        }
??/        \
??'        ^
??=        #
??!        |
??-        ~

Джерело: 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 не надав кількість символів, необхідних для інших мов, крім англійської, було створено ряд національних варіантів, які замінювали деякі менш вживані символи потрібними .

(наголос мій)

Отже, по суті, деякі необхідні персонажі (ті, для яких існує триграф) були замінені в певних національних варіантах. Це призводить до поперемінного подання за допомогою триграфа, що складається з символів, які інші варіанти все ще мали навколо.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.