[c] C에서 >>> = 연산자는 무엇입니까?

동료가 퍼즐로 생각할 때이 C 프로그램이 실제로 어떻게 컴파일되고 실행되는지 알 수 없습니다. 이 >>>=연산자와 이상한 1P1리터럴 은 무엇입니까 ? Clang과 GCC에서 테스트했습니다. 경고가없고 출력은 “???”입니다.

#include <stdio.h>

int main()
{
    int a[2]={ 10, 1 };

    while( a[ 0xFULL?'\0':-1:>>>=a<:!!0X.1P1 ] )
        printf("?");

    return 0;
}



답변

라인 :

while( a[ 0xFULL?'\0':-1:>>>=a<:!!0X.1P1 ] )

digraphs :> 및을 포함 하므로 각각 과로 <:번역 되므로 다음과 같습니다.][

while( a[ 0xFULL?'\0':-1 ] >>= a[ !!0X.1P1 ] )

리터럴 0xFULL은 (와 0xF16 진수 15) 와 동일합니다 . ULL것을 단지 지정 그것이이다 unsigned long long리터럴 . 그래서 어떤 경우에는, 부울로는, 사실 0xFULL ? '\0' : -1평가됩니다에 '\0'문자 리터럴 단순히 그 수치 0.

한편, 0X.1P1A는 리터럴 진수 부동 소수점 2/16 = 0.125 같음. 어쨌든 0이 아닌 경우도 부울로도 true이므로 !!다시 두 번 부정하면을 생성합니다 1. 따라서 모든 것이 다음과 같이 단순화됩니다.

while( a[0] >>= a[1] )

연산자 >>=는 왼쪽 피연산자를 오른쪽 피연산자가 제공 한 비트 수만큼 오른쪽으로 시프트하고 결과를 반환 하는 복합 할당 입니다. 이 경우, 오른쪽 피연산자는 a[1]항상 값 1을 가지므로 다음과 같습니다.

while( a[0] >>= 1 )

또는 동등하게 :

while( a[0] /= 2 )

초기 값 a[0]은 10입니다. 오른쪽으로 한 번 이동 한 후 5가되고 (내림차순) 2, 1, 마지막으로 0이되어 루프가 종료됩니다. 따라서 루프 본문이 세 번 실행됩니다.


답변

그것은 포함하는 다소 모호한 코드 이중 음자 즉, <::>대체 토큰입니다 []각각입니다. 의 일부 사용도 있습니다 조건 연산자 . 도있다 비트 이동 연산자 오른쪽 시프트 할당 >>=.

이것은 더 읽기 쉬운 버전입니다.

while( a[ 0xFULL ? '\0' : -1 ] >>= a[ !!0X.1P1 ] )

그리고 훨씬 더 읽기 쉬운 버전으로, []다음으로 해석되는 값 의 표현식을 대체합니다 .

while( a[0] >>= a[1] )

교체 a[0]하고 a[1]그 값이해야 것이 쉬운 루프, 즉 동등한, 무엇을하고 있는지 알아 내기 위해 :

int i = 10;
while( i >>= 1)

각 반복마다 2 씩 (정수) 나누기를 수행하여 시퀀스를 생성합니다 5, 2, 1.


답변

왼쪽에서 오른쪽으로 표현을 봅시다.

a[ 0xFULL?'\0':-1:>>>=a<:!!0X.1P1 ]

내가 주목하는 첫 번째는의 사용에서 삼항 연산자를 사용하고 있다는 것입니다 ?. 하위 표현식 :

0xFULL ? '\0' : -1

0xFULL0이 아닌 경우 return '\0', 그렇지 않으면 -1. 0xFULL부호없는 긴 접미사 가있는 16 진수 리터럴입니다 unsigned long long. 즉 , 형식의 16 진수 리터럴입니다 . 0xF일반 정수 안에 들어갈 수 있기 때문에 실제로 중요하지 않습니다 .

또한 삼항 연산자는 두 번째 및 세 번째 항의 유형을 공통 유형으로 변환합니다. '\0'다음으로 변환됩니다 int단지 인 0.

0xF이 0보다 크므로 통과합니다. 이제 표현은 다음과 같습니다.

a[ 0 :>>>=a<:!!0X.1P1 ]

다음 :>digraph 입니다. 다음으로 확장되는 구조입니다 ].

a[0 ]>>=a<:!!0X.1P1 ]

>>=부호가있는 오른쪽 시프트 연산자 a입니다. 더 명확하게하기 위해 간격을 둘 수 있습니다.

또한 다음과 같이 <:확장되는 digraph입니다 [.

a[0] >>= a[!!0X.1P1 ]

0X.1P1지수가있는 16 진 리터럴입니다. 그러나 가치에 관계없이 !!0이 아닌 것은 사실입니다. 0X.1P10.125은가되도록 0이 아닌, 어느 :

a[0] >>= a[true]
-> a[0] >>= a[1]

>>=서명 오른쪽 시프트 연산자입니다. 연산자 오른쪽의 값만큼 비트를 앞으로 이동하여 왼쪽 피연산자의 값을 변경합니다. 10이진수로입니다 1010. 단계는 다음과 같습니다.

01010 >> 1 == 00101
00101 >> 1 == 00010
00010 >> 1 == 00001
00001 >> 1 == 00000

>>=a[0]비트가 1 씩 오른쪽으로 시프트 될 때마다 시프트 가 0이 아닌 한, 루프는 계속 작동하므로 연산 결과를 리턴합니다 . 네 번째 시도는 where a[0]0되어 루프가 입력되지 않습니다.

결과적으로 ?세 번 인쇄됩니다.


답변