동료가 퍼즐로 생각할 때이 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
은 (와 0xF
16 진수 15
) 와 동일합니다 . ULL
것을 단지 지정 그것이이다 unsigned long long
리터럴 . 그래서 어떤 경우에는, 부울로는, 사실 0xFULL ? '\0' : -1
평가됩니다에 '\0'
인 문자 리터럴 단순히 그 수치 0
.
한편, 0X.1P1
A는 리터럴 진수 부동 소수점 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
” 0xFULL
0이 아닌 경우 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.1P1
인 0.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
되어 루프가 입력되지 않습니다.
결과적으로 ?
세 번 인쇄됩니다.