Що означає ??! ?? оператор робити на 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.