荔园在线
荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀
[回到开始]
[上一篇][下一篇]
发信人: MUL (MUL), 信区: Program
标 题: 圣诞十二天
发信站: 荔园晨风BBS站 (2005年10月10日17:59:38 星期一), 站内信件
有人分析了,哈哈!
发信人: LosComet (小七其实挺聪明的,就是人有点傻……), 信区: CProgramming
标 题: 圣诞十二天
发信站: 水木社区 (Mon Oct 10 13:20:20 2005), 站内
那天那个程序的分析,今天刚刚从硬盘里翻出来的~~,贴出来吧:
===============================================================================
=
==========
/***************************************************************
你能猜出这段程序的输出结果吗?
许多人都坚信,只要有源代码,他们就总能搞懂代码里所有的玄机。
下面这几行C语言代码就是对这一类人的最大嘲弄:
这只是一段普通的C语言代码罢了。我知道,它也许看上去不那么
好看,似乎这只是一堆无法通过编译的字符垃圾。不过,为什么
你不试一试呢?它的确能通过所有C语言编译器的编译。
我担保你猜不出它的运行结果,试着运行一下,你一定会被输出结
果惊得目瞪口呆。
/* Write by CYNOSURE , cinasure#hotmail bbs.cdut.edu.cn */
****************************************************************/
#include <stdio.h>
main(t,_,a)char *a;{return!0<t?t<3?main(-79,-13,a+main(-87,1-_,
main(-86,0,a+1)+a)):1,t<_?main(t+1,_,a):3,main(-94,-27+t,a)&&t==2?_<13?
main(2,_+1,"%s %d %d\n"):9:16:t<0?t<-72?main(_,t,
"@n'+,#'/*{}w+/w#cdnr/+,{}r/*de}+,/*{*+,/w{%+,/w#q#n+,/#{l+,/n{n+,/+#n+,/#\
;#q#n+,/+k#;*+,/'r :'d*'3,}{w+K w'K:'+}e#';dq#'l \
q#'+d'K#!/+k#;q#'r}eKK#}w'r}eKK{nl]'/#;#q#n'){)#}w'){){nl]'/+#n';d}rw' i;# \
){nl]!/n{n#'; r{#w'r nc{nl]'/#{l,+'K {rw' iK{;[{nl]'/w#q#n'wk nw' \
iwk{KK{nl]!/w{%'l##w#' i; :{nl]'/*{q#'ld;r'}{nlwb!/*de}'c \
;;{nl'-{}rw]'/+,}##'*}#nc,',#nw]'/+kd'+e}+;#'rdq#w! nr'/ ') }+}{rl#'{n' ')# \
}'+}##(!!/")
:t<-50?_==*a?putchar(31[a]):main(-65,_,a+1):main((*a=='/')+t,_,a+1)
:0<t?main(2,2,"%s"):*a=='/'||main(0,main(-61,*a,
"!ek;dc i@bK'(q)-[w]*%n+r3#l,{}:\nuwloca-O;m .vpbks,fxntdCeghiry"),a+1);}
上面这段代码,确实很好玩,这是1988年IOCCC大赛(国家C语言混乱大赛)的一段作品,
这段看起来杂乱无章的代码,它居然能输出一段诗:
On the first day of Christmas my true love gave to me
a partridge in a pear tree.
On the second day of Christmas my true love gave to me
two turtle doves
and a partridge in a pear tree.
On the third day of Christmas my true love gave to me
three french hens, two turtle doves
and a partridge in a pear tree.
On the fourth day of Christmas my true love gave to me
four calling birds, three french hens, two turtle doves
and a partridge in a pear tree.
On the fifth day of Christmas my true love gave to me
five gold rings;
four calling birds, three french hens, two turtle doves
and a partridge in a pear tree.
On the sixth day of Christmas my true love gave to me
six geese a-laying, five gold rings;
four calling birds, three french hens, two turtle doves
and a partridge in a pear tree.
On the seventh day of Christmas my true love gave to me
seven swans a-swimming,
six geese a-laying, five gold rings;
four calling birds, three french hens, two turtle doves
and a partridge in a pear tree.
On the eigth day of Christmas my true love gave to me
eight maids a-milking, seven swans a-swimming,
six geese a-laying, five gold rings;
four calling birds, three french hens, two turtle doves
and a partridge in a pear tree.
On the ninth day of Christmas my true love gave to me
nine ladies dancing, eight maids a-milking, seven swans a-swimming,
six geese a-laying, five gold rings;
four calling birds, three french hens, two turtle doves
and a partridge in a pear tree.
On the tenth day of Christmas my true love gave to me
ten lords a-leaping,
nine ladies dancing, eight maids a-milking, seven swans a-swimming,
six geese a-laying, five gold rings;
four calling birds, three french hens, two turtle doves
and a partridge in a pear tree.
On the eleventh day of Christmas my true love gave to me
eleven pipers piping, ten lords a-leaping,
nine ladies dancing, eight maids a-milking, seven swans a-swimming,
six geese a-laying, five gold rings;
four calling birds, three french hens, two turtle doves
and a partridge in a pear tree.
On the twelfth day of Christmas my true love gave to me
twelve drummers drumming, eleven pipers piping, ten lords a-leaping,
nine ladies dancing, eight maids a-milking, seven swans a-swimming,
six geese a-laying, five gold rings;
four calling birds, three french hens, two turtle doves
and a partridge in a pear tree.
----------------------------------
我是先看到这个结果,然后才看到程序的,第一眼的反应:“人工智能”?!
这种杂乱无章的程序,居然能写出通顺的文章?!天啦,太牛了!!!
不过,我打死也不相信有人工智能可以达到这种境界。。。。。
所以俺决定和它较真儿!
既然是输出文字的东东,那首先看看字符串吧。。。。发现整个程序,只有四个字符串。
"%s %d %d\n"
"@n'+,#'/*{}w+/w#cdnr/+,{}r/*de}+,/*{*+,/w{%+,/w#q#n+,/#{l+,/n{n+,/+#n+,/#\
;#q#n+,/+k#;*+,/'r :'d*'3,}{w+K w'K:'+}e#';dq#'l \
q#'+d'K#!/+k#;q#'r}eKK#}w'r}eKK{nl]'/#;#q#n'){)#}w'){){nl]'/+#n';d}rw' i;# \
){nl]!/n{n#'; r{#w'r nc{nl]'/#{l,+'K {rw' iK{;[{nl]'/w#q#n'wk nw' \
iwk{KK{nl]!/w{%'l##w#' i; :{nl]'/*{q#'ld;r'}{nlwb!/*de}'c \
;;{nl'-{}rw]'/+,}##'*}#nc,',#nw]'/+kd'+e}+;#'rdq#w! nr'/ ') }+}{rl#'{n' ')# \
}'+}##(!!/"
"%s"
"!ek;dc i@bK'(q)-[w]*%n+r3#l,{}:\nuwloca-O;m .vpbks,fxntdCeghiry"
很明显的,第二个字符串是重点怀疑对象,因为它太庞大了,我不相信那么短
的程序里面,如此长(占程序一大半)的东西会不起作用。。。。但它确实是
杂乱无章的呀。。。但是。。。。第二个hint发现了。。。一个符号经常性的
出现哦。。。那就是“#”。。。如果略微知道一点密码学,应该晓得,英文
里面最常出现的字母,一定是“e”!啊呀呀,啊呀呀。。。。是不是应该比
较一下这段文字和打印出来的正文呢?正文重复的太多,有理由相信是用循环
生成的。那么,比较最后一段吧。。。把“#”当作“e”来对比。。。。。
为了缩小范围:我们把##形式的当作ee,能找到什么呢?分别有三段含有
##和ee:
w{%'l##w#' i; § +,}##'*}#nc § }'+}##(!!/
six geese a-layi § ds, three french § a pear tree.
比较以上片段,是不是很容易看出字符对应规则?
拿着这段鸡毛你就可以当令箭了,那段加密后的字符串,原来就是:
"On the
/first/second/third/fourth/fifth/sixth/seventh/eigth/ninth/tenth/elevent
h/twelfth/ day of Christmas my true love gave to me
/twelve drummers drumming, /eleven pipers piping, /ten lords a-leaping,
/nine ladies dancing, /eight maids a-milking, /seven swans a-swimming,
/six geese a-laying, /five gold rings;
/four calling birds, /three french hens, /two turtle doves
and /a partridge in a pear tree.
/"
啊哈,原来。。。原来。。。原来。。。。楼上的程序就是在故弄玄
虚嘛,假动作之一,发现了。。。。。呵呵
不过这才是万里长征,第一步呢。。。要想弄懂它,还得慢慢看。。。
怎么解密呢?程序里面使用了什么高明的算法吗?继续看下去吧。。。
嗯,输出嘛,总该有个东西来负责输出,没有print? 那么putchar也
凑合,果然有个putchar! 可是,为什么是putchar(31[a])呢?31?有
什么奥妙?
嗯嗯嗯。。。看看第四个字符串,长度?啊,不是刚刚好是31×2+1嘛
为什么多了个1?呀呀呀,字符串里面有个\n,不是刚好多1嘛,看看呢?
把这个字符串剖成两半呢?
!ek;dc i@bK'(q)-[w]*%n+r3#l,{}:
\nuwloca-O;m .vpbks,fxntdCeghiry
哦?!这不正好是密码表吗?!Bingo!
putchar(31[a]),这正是指针的一个绝妙应用,原来,就等于putchar(a+31)啊。
原程序我们可以做个手术了:
#include <stdio.h>
main(t,_,a)char *a;{return!0<t?t<3?main(-79,-13,a+main(-87,1-_,
main(-86,0,a+1)+a)):1,t<_?main(t+1,_,a):3,main(-94,-27+t,a)&&t==2?_<13?
main(2,_+1,"%s %d %d\n"):9:16:t<0?t<-72?main(_,t,
"密文")
:t<-50?_==*a?putchar(31[a]):main(-65,_,a+1):main((*a=='/')+t,_,a+1)
:0<t?main(2,2,"%s"):*a=='/'||main(0,main(-61,*a,
"密码表"),a+1);}
可是即使是这样,这程序还是很难懂,没办法,我们来挨个修理那些问号冒号吧!
为便于理解,我还加上了些括号:
main(t,_,a)
char *a;
{
return !0 < t ? (t<3? main(-79,-13,a+main(-87,1-_,main(-86,0,a+1)+a))
:
1),
(t<_?main(t+1,_,a ):0) ,
(main(-94,t-27,a)&&t==2 ? ( _ < 13 ?main(2,_+1,"%s
%d
%d\n"):9) : 16)
: t<0? ( t<-72? main(_,t, "加密文本")
: (t<-50? ( _==*a ? putchar(密码表长度的一
半
[a])
: main(-65,_,a+1)
)
: main((*a=='/')+t,_,a+1)
)
)
: t>0 ? main(2,2,"%s")
:(*a=='/' || main(0,main(-61,*a,"密码表"),a+
1
));
}
试过几次后发现一个重要的问题:return!0<t,居然等价于return 1<t,这是把 !0 直接
当
作1了。。。
这是作者和我们开的第二个玩笑:)
( _ < 13 ?main(2,_+1,"%s %d %d\n"):9) 这里的13是不是与循环次数有关呢?改来看看
,果然就是。
由此可见,根据t的大小,程序分为几个流程:
当
t<-72:main(_,t, "加密文本") ,准备输出文本
-72<=t<-50:_==*a时候输出解密字符并返回1,否则 main(-65,_,a+1),可见这里的参
数-65还是在-72和-50之间。
这是在重复调用自身,指针a在寻找密
码
。
-50<=t<0:main((*a=='/')+t,_,a+1) 和上面差不多,这个简单的说就是将指针移
动
到第-t个“/”后面。
0==t:(*a=='/' || main(0,main(-61,*a,"密码表"),a+1)),顺序输出字符(调用main(
-
61....)),直到遇到“/”。
注意: || 运算符特点,左式为真的话,
不再判断右式。
1==t:main(2,2,"%s")
2=<t<循环数+1: (t<3? main(-79,-13,a+main(-87,1-_,main(-86,0,a+1)+a))
:
1),
(t<_?main(t+1,_,a ):0) ,
(main(-94,t-27,a)&&t==2 ? ( _ < 13 ?main(2,_+1,"%s
%d
%d\n"):9) : 16)
注意这是个逗号表达式,表示顺序执行,那就是从左往右一个一个的求值,最后整个
表
达式的结果
是最后一个求值的结果。
循环数+1=<t:不用管它内容了,整个程序没有机会进入它。
第一次调用的时候,t和_都等于1,所以先进入 main(2,2,"%s");, 顺序执行程序,
注意到在t<-72或t=2的时候,第三个参数a是没用的,所以,"%s %d %d\n"和"%s",在程
序中是没有用处的,
main(-79,-13,a+main(-87,1-_,main(-86,0,a+1)+a)) : 1)也就等于main(-79,-13,main(-
8
7,1-_,main(-86,0,随便什么)) : 1)
接下来就很好理解了,可以把“/”当作数组的分隔符,那么把密文看作个数组:
str[0]=On the
str[1]=first
str[2]=second
str[3]=third
str[4]=fourth
str[5]=fifth
str[6]=sixth
str[7]=seventh
str[8]=eigth
str[9]=ninth
str[10]=tenth
str[11]=eleventh
str[12]=twelfth
str[13]= day of Christmas my true love gave to me \n
str[14]=twelve drummers drumming,
str[15]=eleven pipers piping,
str[16]=ten lords a-leaping, \n
str[17]=nine ladies dancing,
str[18]=eight maids a-milking,
str[19]=seven swans a-swimming,\n
str[20]=six geese a-laying,
str[21]=five gold rings; \n
str[22]=four calling birds,
str[23]=three french hens,
str[24]=two turtle doves \nand
str[25]=a partridge in a pear tree. \n\n
程序的主题就在于这个分支:2=<t<循环数+1,从main(2,2,"%s")进入,t,_初始值都是2:
(t<3? main(-79,-13, 再然后,打印str[13],
main(-87,1-_, 然后执行这里,打印str[_-1],因为后面有个循
环,_是从2到13。
main(-86,0,1))) : 1), 首先执行这里,输出数组元素,第二个参数乘-1便是下标。
这
里为0,打印str[0]=On the
(t<_?main(t+1,_,a ):0) , 然后,循环str[27-t'],t'
从
t循环到_,第一次因为t=_就跳过这里,继续后面的。
在每次循环中由于t'>=2,
所以后面的操作,只打印str[27-t'],并不执行
分支 main(2,_+1,"%s
%d %
d\n");
(main(-94,t-27,a)&&t==2?( _ < 13 ?main(2,_+1,""):9) : 16) 当上面的循环完
了后,再执行此判断,
也就是,打印str[
2
7-2]=a partridge in a pear tree. \n\n
最后,循环调用ma
i
n(2,3,"")一直到main(2,13,"")
依次打印12段的内
容。
ok,这就是程序全部流程了。。。。。。打完收工~~~
这作者实在爱和大家开玩笑,文本加密不说,还用!0,逗号,问号,一堆东西,总是让人
想
入霏霏呀:)
/* Write by CYNOSURE , cinasure#hotmail bbs.cdut.edu.cn */
===============================================================================
=
==========
--
main(_){for(--_;putchar(_++["J!Mpwf!Zpv\1"]-1););}
※ 来源:·水木社区 http://newsmth.net·[FROM: 221.2.163.*]
--
VENI VIDE VICI
※ 来源:·荔园晨风BBS站 bbs.szu.edu.cn·[FROM: 192.168.1.106]
[回到开始]
[上一篇][下一篇]
荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店