让我们澄清一下。
缩进:
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转变 = ";;;====~$:: 199”(我* 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选择表值的高八进制数字(对于i%8 = 0,1,4,5)或低八进制数字(对于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
注意,作者对前两个表项使用了空结束符(狡猾!)。
这是在7段显示之后设计的,7段作为空白。所以,第一个表中的条目必须定义被点亮的段。
第一张表格
__TIME__是预处理器定义的一个特殊宏。它展开为一个字符串常量,包含预处理器运行的时间,形式为“HH:MM:SS”。注意它正好包含8个字符。请注意,0-9的ASCII值为48到57,并且:的ASCII值为58。每行输出64个字符,因此__TIME__的每个字符还剩下8个字符。
因此,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位ASCII,高位总是被清除。因此,段表中的7总是作为空白输出。第二个表是这样的,7是空的:
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);}
我们得到了
!! !! !!
!! !! !! !! !! !! !! !! !!
!! !! !! !! !! !! !! !! !!
!! !! !! !!
!! !! !! !! !! !! !! !! !!
!! !! !! !! !! !! !! !! !!
!! !! !!
不出我们所料。它看起来不像原来的那样坚固,这就解释了为什么作者选择使用他所做的表格。