首页 > 代码库 > 1987年国际C语言混乱代码大赛获奖的一行代码

1987年国际C语言混乱代码大赛获奖的一行代码

            


                    macb() ? lpcbyu(&gbcq/_\021%ocq\012\0_=w(gbcq)/_dak._=}_ugb_[0q60)s+

          

          这是CoolShell博主之前做了一个很有意思的在线puzzle,仿照一些前端过关的游戏,做了几个和程序员有关的迷题,一个通关游戏,这个事测试的第二题。并为通关的前十名送上《Unix环境高级编程(第三版)》(感谢@出版圈郭志敏 赞助)或一个马克杯(感谢@linux命令行精选网 赞助))这些谜题很有趣同时也有一定的难度。由于水平有限,我并没有通关,但我感觉这些东西确实很有意思很值得一做,还是可以从中学到不少东西的。

            这个是原游戏测试的链接http://fun.coolshell.cn/。这个测试我觉得还是蛮有趣的,刚一进去看到页面就懵了无从下手啊。限于个人能力及知识面狭窄,在作者的提示下了解到这是一段与Brainfuck编程语言有关的字段。网上一番搜索查看资料后,求解答到答案是“welcome.html”。具体求解实现过程看Brainfuck——让你脑子凌乱的程序语言




        一看到这个键盘就发现跟我们平常键盘布局不一样。于是就想到,这个题就是将图中键盘的字符与我们电脑键盘上相应位置的字符替换。于是我很快的做了,结果如下

main(){printf(&unix["\021%six\012\0"],(unix)["have"]+"fun"-0x60);}
 
        看到这里有点傻眼了,难道这就是传说中的C语言混乱代码。这是4th International Obfuscated C Code Contest (1987),由AT&T Bell Labs的David Korn所写。历届国际C语言混乱代码大赛作品欣赏。将代码COPY后粘贴到IDE里面,编译提示"unix was notdeclared in this scope"。好吧,没有声明,那果断的用#define宏定义个值呗
#define unix 1
         尼玛,居然运行出结果unix。这结果真是令人意向不到,混乱代码就是一个字“乱”的有才。

         通过查看相关资料,最后算是弄清了它的真面目了。


首先复习一点知识:

        字符型常量和ASCII字符集。每个字符在内存中占用一个字节,用来存储它的ASCII码值。因此,C语言的字符具有数值特征,可以像整数一样参加运算。

       转义字符:有一些字符,如回车符(‘\r‘),换行符(‘\n‘)等控制符号,它们不能在屏幕上显示,也无法从键盘输入,只能用转义字符表示。转义字符由反斜杠加上一个字符或数字组成,它将反斜杠后面的字符或数字转换成别的意义。

\ddd        1-3位八进制字符所代表的字符,如\102='B'    
\xhh        1-2位十六进制字符所代表的字符,如\x41='A'
printf("%x",'\n');printf("%x",'\r');//换行符,回车符的ASCII码值分别为a,d,即十进制的10,13
       最后,很重要的一点啦
int a[3]={1,2,3};
printf("%d	%d\n",a[2], 2[a]);
//没错,你的眼睛却是没有看错。他居然真的都输出是3</span>
       以上翻阅自《C和指针》,arry[2]和2[arry]是等价的,这个诡异技巧之所以可行,源于C语言实现下表的方法。虽然两者并无差别但毫无疑问这样影响程序的可阅读性啦。不建议大面积推广造成不必要的杀伤!

       看到这里,我们可以将上面的翻译过的那段代码再度转换一下,如下:

main(){printf(&unix["\021%six\n"],(unix)["have"]+"fun"-0x60);}	
//\021=17,ASCII字符为DC1。它是一个字符 ;\012=10=0xa='\n',\0='0',则 
main(){printf(&"DC1%six\n\0"[unix],"have"[unix]+"fun"-0x60);}
//令unix=1,则
main(){printf(&"DC1%six\n"[1],"have"[1]+"fun"-0x60);}
//&"DC1%six\n",去字符串中下标1处的地址,则
main(){printf("%six\n",'a'-0x60+"fun");}
//a的ASCII只为97=0x61,则
main(){printf("%six\n","fun"+1);}
以上等同main(){printf("%six\n","un");}
         写到这里,整个过程应该很清晰明白了。OK,接着看下一题去