이 C 프로그램은 어떻게 작동합니까?
main(_){_^448&&main(-~_);putchar(--_%64?32|-~7[__TIME__-_/8%8][">'txiZ^(~z?"-48]>>";;;====~$::199"[_*2&8|_/64]/(_&2?1:8)%8&1:10);}
그대로 테스트됩니다 (에서 테스트 됨 gcc 4.6.3
). 컴파일 할 때 시간을 인쇄합니다. 내 시스템에서 :
!! !!!!!! !! !!!!!! !! !!!!!!
!! !! !! !! !! !! !! !!
!! !! !! !! !! !! !! !!
!! !!!!!! !! !! !! !! !! !!!!!!
!! !! !! !! !! !! !!
!! !! !! !! !! !! !!
!! !!!!!! !! !! !! !!!!!!
출처 : sykes2-한 줄의 시계 , sykes2 작가의 힌트
힌트 : 기본값마다 컴파일 경고가 없습니다. 로 컴파일 -Wall
하면 다음과 같은 경고가 발생합니다.
sykes2.c:1:1: warning: return type defaults to ‘int’ [-Wreturn-type]
sykes2.c: In function ‘main’:
sykes2.c:1:14: warning: value computed is not used [-Wunused-value]
sykes2.c:1:1: warning: implicit declaration of function ‘putchar’ [-Wimplicit-function-declaration]
sykes2.c:1:1: warning: suggest parentheses around arithmetic in operand of ‘|’ [-Wparentheses]
sykes2.c:1:1: warning: suggest parentheses around arithmetic in operand of ‘|’ [-Wparentheses]
sykes2.c:1:1: warning: control reaches end of non-void function [-Wreturn-type]
답변
난독 화하자.
들여 쓰기 :
main(_) {
_^448 && main(-~_);
putchar(--_%64
? 32 | -~7[__TIME__-_/8%8][">'txiZ^(~z?"-48] >> ";;;====~$::199"[_*2&8|_/64]/(_&2?1:8)%8&1
: 10);
}
이 혼란을 풀기위한 변수 소개 :
main(int i) {
if(i^448)
main(-~i);
if(--i % 64) {
char a = -~7[__TIME__-i/8%8][">'txiZ^(~z?"-48];
char b = a >> ";;;====~$::199"[i*2&8|i/64]/(i&2?1:8)%8;
putchar(32 | (b & 1));
} else {
putchar(10); // newline
}
}
참고 -~i == i+1
때문에의 보수의를. 따라서 우리는
main(int i) {
if(i != 448)
main(i+1);
i--;
if(i % 64 == 0) {
putchar('\n');
} else {
char a = -~7[__TIME__-i/8%8][">'txiZ^(~z?"-48];
char b = a >> ";;;====~$::199"[i*2&8|i/64]/(i&2?1:8)%8;
putchar(32 | (b & 1));
}
}
이제는와 a[b]
동일b[a]
하고 -~ == 1+
변경 사항을 다시 적용 하십시오.
main(int i) {
if(i != 448)
main(i+1);
i--;
if(i % 64 == 0) {
putchar('\n');
} else {
char a = (">'txiZ^(~z?"-48)[(__TIME__-i/8%8)[7]] + 1;
char b = a >> ";;;====~$::199"[(i*2&8)|i/64]/(i&2?1:8)%8;
putchar(32 | (b & 1));
}
}
재귀를 루프로 변환하고 좀 더 간단하게 몰래 가져옵니다.
// please don't pass any command-line arguments
main() {
int i;
for(i=447; i>=0; i--) {
if(i % 64 == 0) {
putchar('\n');
} else {
char t = __TIME__[7 - i/8%8];
char a = ">'txiZ^(~z?"[t - 48] + 1;
int shift = ";;;====~$::199"[(i*2&8) | (i/64)];
if((i & 2) == 0)
shift /= 8;
shift = shift % 8;
char b = a >> shift;
putchar(32 | (b & 1));
}
}
}
반복 당 하나의 문자를 출력합니다. 64 번째 문자마다 줄 바꿈을 출력합니다. 그렇지 않으면, 한 쌍의 데이터 테이블을 사용하여 출력 할 내용을 파악하고 문자 32 (공백) 또는 문자 33 (a !
)을 넣습니다 . 첫 번째 테이블 ( ">'txiZ^(~z?"
)은 각 문자의 모양을 설명하는 10 개의 비트 맵 세트이며, 두 번째 테이블 ( ";;;====~$::199"
)은 비트 맵에서 표시 할 적절한 비트를 선택합니다.
두 번째 테이블
두 번째 테이블 인을 살펴 보자 int shift = ";;;====~$::199"[(i*2&8) | (i/64)];
. i/64
행 번호 (6 ~ 0)이고 i*2&8
8 iff i
는 4, 5, 6 또는 7 mod 8입니다.
if((i & 2) == 0) shift /= 8; shift = shift % 8
테이블 값 의 상위 8 진수 ( i%8
0,1,4,5) 또는 하위 8 진수 ( i%8
2,3,6,7)를 선택합니다. 시프트 테이블은 다음과 같이 보입니다.
row col val
6 6-7 0
6 4-5 0
6 2-3 5
6 0-1 7
5 6-7 1
5 4-5 7
5 2-3 5
5 0-1 7
4 6-7 1
4 4-5 7
4 2-3 5
4 0-1 7
3 6-7 1
3 4-5 6
3 2-3 5
3 0-1 7
2 6-7 2
2 4-5 7
2 2-3 3
2 0-1 7
1 6-7 2
1 4-5 7
1 2-3 3
1 0-1 7
0 6-7 4
0 4-5 4
0 2-3 3
0 0-1 7
또는 표 형식
00005577
11775577
11775577
11665577
22773377
22773377
44443377
저자는 처음 두 테이블 항목에 대해 null 종결자를 사용했습니다 (sneaky!).
이것은 7 세그먼트 디스플레이 후에 7
s를 공백으로 하여 설계되었습니다 . 따라서 첫 번째 테이블의 항목은 점등되는 세그먼트를 정의해야합니다.
첫 번째 테이블
__TIME__
전처리기에 의해 정의 된 특수 매크로입니다. 전처리 기가 실행 된 시간을 포함하는 문자열 상수로 확장됩니다 (형식) "HH:MM:SS"
. 정확히 8자를 포함하는지 확인하십시오. 0-9의 ASCII 값 :
은 48-57 이며 ASCII 값은 58입니다. 출력은 한 줄에 64 자이므로의 문자 당 8 자입니다 __TIME__
.
7 - i/8%8
따라서 그 색인 __TIME__
은 현재 출력되고 있습니다 ( 아래 7-
로 반복하기 때문에 필요합니다 i
). 따라서 출력되는 t
특성입니다 __TIME__
.
a
입력에 따라 이진수로 다음과 같습니다 t
.
0 00111111
1 00101000
2 01110101
3 01111001
4 01101010
5 01011011
6 01011111
7 00101001
8 01111111
9 01111011
: 01000000
각 숫자는 7 세그먼트 디스플레이에서 점등되는 세그먼트를 설명 하는 비트 맵 입니다. 문자는 모두 7 비트 ASCII이므로 높은 비트는 항상 지워집니다. 따라서 7
세그먼트 테이블에서 항상 공백으로 인쇄합니다. 두 번째 테이블은 7
s를 공백으로 사용하여 다음과 같이 보입니다 .
000055
11 55
11 55
116655
22 33
22 33
444433
따라서, 예를 들어, 4
이다 01101010
(비트 1, 3, 5, 6 세트), 인쇄 등
----!!--
!!--!!--
!!--!!--
!!!!!!--
----!!--
----!!--
----!!--
코드를 실제로 이해하고 있음을 보여주기 위해 다음 표를 사용하여 출력을 약간 조정 해 보겠습니다.
00
11 55
11 55
66
22 33
22 33
44
이것은로 인코딩됩니다 "?;;?==? '::799\x07"
. 예술적인 목적으로, 우리는 문자 몇 개에 64를 더할 것입니다 (낮은 6 비트 만 사용되므로 출력에 영향을 미치지 않습니다). 이 있습니다 "?{{?}}?gg::799G"
(참고는 8 캐릭터가 사용되지 않는 것을, 그래서 우리는 실제로 우리가 원하는대로 그것을 만들 수 있습니다). 새 코드를 원래 코드에 넣습니다.
main(_){_^448&&main(-~_);putchar(--_%64?32|-~7[__TIME__-_/8%8][">'txiZ^(~z?"-48]>>"?{{?}}?gg::799G"[_*2&8|_/64]/(_&2?1:8)%8&1:10);}
우리는 얻는다
!! !! !!
!! !! !! !! !! !! !! !! !!
!! !! !! !! !! !! !! !! !!
!! !! !! !!
!! !! !! !! !! !! !! !! !!
!! !! !! !! !! !! !! !! !!
!! !! !!
우리가 예상 한대로. 저자가 자신이 한 테이블을 사용하기로 선택한 이유를 설명하는 것은 원본보다 견고하지 않습니다.
답변
더 쉽게 읽을 수 있도록이 형식을 지정하십시오.
main(_){
_^448&&main(-~_);
putchar((--_%64) ? (32|-(~7[__TIME__-_/8%8])[">'txiZ^(~z?"-48]>>(";;;====~$::199")[_*2&8|_/64]/(_&2?1:8)%8&1):10);
}
따라서 인수없이 실행하면 _ (argc는 일반적으로)입니다 1
. main()
재귀 적으로 호출하고 결과를 -(~_)
(음수 비트 NOT의 _
) 결과를 전달 하므로 실제로 448 회귀가 발생합니다 (조건 만 _^448 == 0
).
그것을 취하면, 64 개의 64 줄 너비의 선 (외부 삼항 조건 및 448/64 == 7
)이 인쇄됩니다. 좀 더 깔끔하게 다시 작성해 보겠습니다.
main(int argc) {
if (argc^448) main(-(~argc));
if (argc % 64) {
putchar((32|-(~7[__TIME__-argc/8%8])[">'txiZ^(~z?"-48]>>(";;;====~$::199")[argc*2&8|argc/64]/(argc&2?1:8)%8&1));
} else putchar('\n');
}
이제 32
ASCII 공간의 십진수입니다. 공백이나 ‘!’를 인쇄합니다. (33은 ‘!’이므로 &1
끝에 ‘ ‘)입니다. 가운데의 얼룩에 초점을 맞추겠습니다.
-(~(7[__TIME__-argc/8%8][">'txiZ^(~z?"-48]) >>
(";;;====~$::199"[argc*2&8|argc/64]) / (argc&2?1:8) % 8
다른 포스터가 말했듯 __TIME__
이 프로그램의 컴파일 시간이며 문자열이므로 문자열 산술이 진행되고 배열 첨자를 양방향으로 활용하는 것이 좋습니다. a [b]는 b [a]와 같습니다 문자 배열 용.
7[__TIME__ - (argc/8)%8]
에서의 처음 8 자 중 하나를 선택 __TIME__
합니다. 그런 다음 색인화됩니다 [">'txiZ^(~z?"-48]
(0-9 문자는 48-57 소수). 이 문자열의 문자는 ASCII 값으로 선택되어 있어야합니다. 동일한 문자 ASCII 코드 조작이 표현식을 통해 계속되어 ”또는 ‘!’가 인쇄됩니다. 캐릭터 글리프 내의 위치에 따라
답변
다른 솔루션에 더하는 것은와 -~x
같으 x+1
므로 ~x
같습니다 (0xffffffff-x)
. 이것은 동일 (-1-x)
하므로, 2 초 보완에 -~x
있다 -(-1-x) = x+1
.
답변
나는 모듈로 산술을 난독 화하고 재귀를 제거했습니다.
int pixelX, line, digit ;
for(line=6; line >= 0; line--){
for (digit =0; digit<8; digit++){
for(pixelX=7;pixelX > 0; pixelX--){
putchar(' '| 1 + ">'txiZ^(~z?"["12:34:56"[digit]-'0'] >>
(";;;====~$::199"[pixel*2 & 8 | line] / (pixelX&2 ? 1 : 8) ) % 8 & 1);
}
}
putchar('\n');
}
조금 더 확장 :
int pixelX, line, digit, shift;
char shiftChar;
for(line=6; line >= 0; line--){
for (digit =0; digit<8; digit++){
for(pixelX=7;pixelX >= 0; pixelX--){
shiftChar = ";;;====~$::199"[pixelX*2 & 8 | line];
if (pixelX & 2)
shift = shiftChar & 7;
else
shift = shiftChar >> 3;
putchar(' '| (">'txiZ^(~z?"["12:34:56"[digit]-'0'] + 1) >> shift & 1 );
}
}
putchar('\n');
}