무엇입니까 ??! ??! 연산자는 C에서합니까?


1990

나는 다음과 같은 C 줄을 보았습니다.

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

올바르게 컴파일되어 정상적으로 실행되는 것 같습니다. 오류가 발생했는지 확인하고 있으면 오류를 처리하는 것 같습니다. 그러나 나는 그것이 실제로 무엇을하고 있는지, 어떻게하고 있는지 잘 모르겠습니다. 프로그래머가 오류에 대한 감정을 표현하려고하는 것처럼 보입니다.

나는 ??!??!어떤 프로그래밍 언어로도 이전에 본 적이 없으며 어디서나 그에 대한 문서를 찾을 수 없습니다. (Google은와 같은 검색어를 지원하지 않습니다 ??!??!). 그 기능은 무엇이며 코드 샘플은 어떻게 작동합니까?


44
@ PeterOlson, 어떻게 !ErrorHasOccurred() ??!???! HandleError();컴파일 할 것으로 기대 하십니까? 그렇습니다 ??! ??? !. 요점을 증명?
CVn

31
깨끗한 코드를 읽으십시오. ErrorHasOccured ()는 ErrorHasNotOccured ()로 리팩토링되어야하며 느낌표를 정리해야합니다.
KadekM

17
오히려 ErrorHasOccured() && HandleError()나 자신을 선호 합니다. Lua도 그렇게합니다.
휴고 징크

76
@KadekM, 부정을 함수 이름으로 옮기는 것은 깨끗한 코드가 아니라 오히려 반대입니다.
marcelm

14
검색 엔진을 사용하여 죽음과 싸운 후 여기에 온 사람을위한 참고 사항 : SymbolHound 는 기호 검색에 도움을 줄 수 있습니다.
Jakob

답변:


1579

??!로 번역 된 3|입니다. 그래서 그것은 말합니다 :

!ErrorHasOccured() || HandleError();

단락으로 인해 다음과 같습니다.

if (ErrorHasOccured())
    HandleError();

금주의 전문가 (C ++로 거래하지만 여기서는 관련성이 있음), 내가 이것을 집어 들었습니다.

주석에서 또는 @DwB 의 가능한 기원은 EBCDIC이 어렵 기 때문에 (더 이상) 주석에서 지적한 바와 같습니다. IBM developerworks 보드에 대한 토론은 해당 이론을 지원하는 것으로 보입니다.

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

3 중 시퀀스는 ISO / IEC 646에 설명 된대로 7 비트 미국 ASCII 코드 세트의 서브 세트 인 고정 코드 세트에 정의되지 않은 문자를 입력 할 수있게합니다.


378
키보드에 예를 들어 '|'가없는 경우를 위해 원래 삼단 법이 필요했습니다. 상징. 프로그래머가 고의적으로 성가 시거나 기괴한 편집자 인 '기능'
Martin Beckett

36
예,에 해당합니다 if (ErrorHasOccured()) HandleError(). 고맙게도 일반적으로 펄 코드에서이 관용구 만 만납니다.
user786653

22
반드시 EBCDIC 일 필요는 없습니다. 3 개의 그래프가 필요한 문자 세트는 ISO-646에서 변하지 않는 문자 세트와 거의 정확히 일치합니다 (예 : 기존 '국가 아스키'표준).
Random832

52
완전히 읽을 수있는 대안은 ErrorHasOccurred() && HandleError();셸 스크립팅에 익숙한 경우입니다. :)
Yam Marcovic

18
@SparkyRobinson, "ErrorHasOcurred가 없거나 HandleError를 처리해야합니다"로 읽습니다.
Omar Antolín-Camarena

453

글쎄, 이것이 일반적으로 존재하는 이유는 아마도 당신의 예제에 존재하는 이유와는 다를 것입니다.

이 모든 것은 반세기 전에 하드 카피 통신 터미널을 컴퓨터 사용자 인터페이스로 사용하여 시작되었습니다. 초기 유닉스와 시대에 그것은 ASR-33 텔레타이프였습니다.

이 장치는 느리고 (10cps) 시끄럽고 못 생겼으며 ASCII 문자 세트의보기는 0x5f로 끝났으므로 아무 키도 갖지 않았습니다 (그림을 자세히보십시오).

{ | } ~ 

3 가지 그래프 는 특정 문제를 해결하기 위해 정의되었습니다. 아이디어는 C 프로그램이 ASR-33에있는 ASCII 서브 세트를 사용하고 다른 환경에서 높은 ASCII 값이 누락 될 수 있다는 것입니다.

귀하의 예는 실제로 두 가지 ??!의미 |를 가지고 있으므로 결과는 다음과 같습니다 ||.

그러나, 거의 정의에 의해 C 코드를 작성하는 사람들은, 현대적인 장비를 가지고 일을 내 생각이 그래서 : 사람, 과시하거나 스스로가를 즐겁게 당신이 찾고있는 코드에서 부활절 달걀의 종류를 떠나.

확실히 효과가 있었으므로 매우 인기있는 SO 질문으로 이어졌습니다.

ASR-33 텔레타이프

                                            ASR-33 텔레타이프


1. 그 문제를 위해, ANSI 그래프에 의해 3 가지 그래프가 만들어졌다. ANSI위원회는 C가 큰 성공을 거둔 후에 처음 만났기 때문에 원래의 C 코드 나 코더 중 어느 것도 그것을 사용하지 않았을 것이다.


18
키보드와 문자 세트에서 문자가 누락 된 것은 아닙니다. Commodore 64는 30 대 후반 이상에서 많은 사람들에게 더 친숙 할 것입니다.이 경우 "ASCII"는 ASCII가 아니기 때문에 표시된 문자 세트에는 중괄호가 부족하고 막대와 물결표가 모두 표시됩니다. . ECMA-6 (거의 항상 ASCII이지만 US-ASCII는 아님)에는 18 개의 지역별 코드가 있지만 어떤 코드인지는 알 수 없습니다. 영국 "ASCII"에서 확실히 말할 수있는 한 가지는 #로 대체되었습니다 £. 다른 지역에서는 아마도 "ASCII"는 괄호 등이 없었을 것입니다.
Steve314

7
Atari 8 비트 컴퓨터에 대한 유사한 ATASCII 문자 세트에도 {}와 ~ 및`가 부족했습니다.
dan04

42
위키 백과 기사를 참조하십시오 . 나는 7 비트 국가 문자 세트의 시대를 여전히 기억할 정도로 나이가 들었습니다 (그러나 그들은 여전히 ​​어둡지 않은 어두운 구석에 남아 있다고 확신하지만) 내가 처음 배운 책에서 C에 대해 경고해야한다는 것을 알았습니다. 잘못된 문자셋 if (x || y) { a[i] = '\0'; }처럼 보일 가능성이 if (x öö y) ä aÄiÅ = 'Ö0'; å있습니다.
Ilmari Karonen

9
또 다른 흥미로운 역사적 메모는 유닉스 (C 플랫폼이 큰 플랫폼)가 기본 알파벳 값에서 대문자가 아닌 소문자에 대한 첫 번째 시스템 (그리고 아마도 첫 번째 전체) 일 수 있다는 것입니다. 나는 많은 현대 시스템을 내 눈으로 보지 못했지만 이것이 정교함의 진정한 표시라고 생각합니다. 실제로 유일하게 괜찮은 OS 일뿐만 아니라, Unix는 또한 대소 문자를 바꾸지 않고 대문자를 소문자로 변환했습니다. 그 사람들은 정말 시원했습니다.
DigitalRoss

16
재미있는 이야기 : IBM RS / 6000 워크 스테이션의 XL Fortran 컴파일러는 XL C 컴파일러에서 개발되었습니다. 처음 몇 번의 릴리스에서는 실수로 삼부작 처리를 떠났기 때문에 C 삼부작으로 잘못 해석 된 합법적 인 포트란 문자 시퀀스 (리터럴 문자열 IIRC)가 있었기 때문에 흥미로운 버그가 발생했습니다!
Phil Perry

166

C trigraph 입니다. ??!입니다 |, ??!??!연산자도 마찬가지 입니다||


5
trigraph는 일부 키보드에 현재 가지고있는 모든 키가없는 기간에서 나왔습니다. 또한 일부 텍스트 편집기가 특별한 것들을 위해 특수 문자를 예약했을 때도 유지됩니다. 그것은 주로 과거와 퀴즈 인 에이 블러의 유물입니다.)
Joel Falcou

5
일부 키보드에는 분명히 "|"가 없기 때문에 따라서 어떤 사람들은 필요한 기호를 제공하는 삼중 그래프가 나타날 때까지 키보드를 반복적으로 누르는 것 외에는 옵션이 없습니다.
Owl

그리고 <iso646.h>헤더 파일이 있습니다.
David R Tribble

149

이미 언급 한대로 ??!??!본질적으로 두 가지이다 trigraph를 ( ??!그리고 ??!다시)에 대체 번역 얻을 함께 헝클어 ||즉, 논리적 OR 전처리에 의해.

모든 3 점을 포함하는 다음 표는 대체 3 점 조합을 명확하게하는 데 도움이됩니다.

Trigraph   Replaces

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

출처 : C : A Reference Manual 5th Edition

같은 모양이있는 trigraph 라 그래서 ??(??)결국에 매핑합니다 [], ??(??)??(??)대체 얻을 것이다 [][]등등, 당신은 아이디어를 얻을.

전처리 과정에서 삼중 그래프가 대체되므로 cpp바보 같은 trigr.c프로그램을 사용하여 출력을 직접 볼 수 있습니다 .

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

그리고 그것을 처리 :

cpp -trigraphs trigr.c 

당신은 콘솔 출력을 얻을 것이다

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

알 수 있듯이 옵션 -trigraphs을 지정해야합니다. 그렇지 않으면 cpp경고가 표시됩니다. 이것은 삼분법이 어떻게 과거의 것이며 현대에 가치가없는 것을 의미합니다 .


3 부작의 도입에 대한 이론적 근거 는 ISO / IEC 646의 히스토리 섹션을 볼 때 더 잘 이해됩니다 .

ISO / IEC 646과 그 이전의 ASCII (ANSI X3.4)는 통신 산업의 문자 인코딩에 관한 기존 관행을 크게 승인했습니다.

ASCII는 영어 이외의 언어에 필요한 여러 문자를 제공하지 않았으므로 덜 사용되는 일부 문자를 필요한 문자로 대체하는 여러 가지 국가 변형이 만들어졌습니다 .

(강조 광산)

따라서 본질적으로 일부 필요한 문자 (삼중 그래프가있는 문자)가 특정 국가 변형으로 대체되었습니다. 이것은 다른 변형이 여전히 가지고있는 문자로 구성된 삼중 그래프를 사용하여 대체 표현으로 이어집니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.