難読化を解除しましょう。
インデント:
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
2の補数のために注意してください。したがって、
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));
}
}
}
これにより、反復ごとに1文字が出力されます。64文字ごとに改行を出力します。それ以外の場合は、1組のデータテーブルを使用して何を出力するかを判断し、文字32(スペース)または文字33(a !
)を配置します。最初のテーブル(">'txiZ^(~z?"
)は、各文字の外観を記述する10個のビットマップのセットであり、2番目のテーブル(";;;====~$::199"
)は、ビットマップから表示する適切なビットを選択します。
2番目のテーブル
まず、2番目のテーブルを調べてみましょうint shift = ";;;====~$::199"[(i*2&8) | (i/64)];
。i/64
行番号(6から0)でi*2&8
あり、8である場合i
は、4、5、6 、または7 mod 8です。
if((i & 2) == 0) shift /= 8; shift = shift % 8
テーブル値の上位8進数(i%8
= 0、1、4、5の場合)または下位8進数(= 2、3、6、7の場合)を選択しi%8
ます。シフトテーブルは次のようになります。
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
著者は最初の2つのテーブルエントリ(不正な!)にnullターミネータを使用したことに注意してください。
これは、7セグメントディスプレイの後に設計されており、7
sをブランクとして使用します。したがって、最初のテーブルのエントリは、点灯するセグメントを定義する必要があります。
最初のテーブル
__TIME__
プリプロセッサによって定義された特別なマクロです。これは、プリプロセッサが実行された時刻を含む文字列定数に展開されます"HH:MM:SS"
。正確に8文字が含まれていることを確認してください。0〜9にはASCII値48〜57と:
ASCII値58があることに注意してください。出力は1行あたり64文字なので、1文字あたり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
セグメントテーブルでは常に空白として印刷されます。2番目のテーブルは、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);}
我々が得る
!! !! !!
!! !! !! !! !! !! !! !! !!
!! !! !! !! !! !! !! !! !!
!! !! !! !!
!! !! !! !! !! !! !! !! !!
!! !! !! !! !! !! !! !! !!
!! !! !!
予想通り。それはオリジナルほどしっかりした見た目ではありません、それは著者が彼がしたテーブルを使うことを選んだ理由を説明しています。
printf("%d", _);
の先頭にmain
プリント:pastebin.com/HHhXAYdJを