12天圣诞节程序怎样运行?
1988 年,一个令人印象深刻且令人敬畏的 C 代码,代号为 xmas.c,在国际混淆 C 代码竞赛中获胜。
该程序甚至比其输出的“压缩”类型还要小,代表了文本压缩标准的全新方式。评委们认为,这个程序像是随意敲击键盘所得到的。
但该程序神奇地打印出12天圣诞节的歌词,仅仅几句话的C代码!
下面来一步步搞清楚程序怎样运行的。
1 作者源代码,一些乱字符的感觉,好几个main~
#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);
}
2 编译,运行,看看结果,嗯,小看这几个乱乱的代码了,这是12天圣诞节(The Twelve Days Of Christmas)的歌词,好神奇^@^
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 -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 eighth day of Christmas my true love gave to me
eight maids a-milking, seven swans -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 -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 -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 -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 -swimming,
six geese a-laying, five gold rings;
four calling birds, three french hens, two turtle doves
and a partridge in a pear tree.
“圣诞节的十二天”是一首英国圣诞特别颂歌,于 1780 年代左右出版,据说它是在英国女王伊丽莎白一世受迫害期间躲藏起来的天主教徒写的。它的创作是为了在不引起政府官员注意的情况下帮助教给孩子们关于天主教信仰的文章,使用形象化描述作为工具以帮助孩子们记忆。这首歌代表了在圣诞节十二天的每一天逐渐给予的盛大礼物。圣诞节的十二天是从圣诞节(12 月 25 日)开始的快乐节日。这也被也称为圣诞节节期(Christmastide and Twelvetide)。
4 查看下汇编代码
Address Hex dump Command Comments00401000 /$ 55 PUSH EBP ;a.00401000(guessed Arg1,Arg2,Arg3)
00401001 |. 89E5 MOVEBP,ESP00401003 |. 81EC 04000000 SUB ESP,4
00401009 |. 90 NOP!0<t0040100A |. B8 01000000 MOV EAX,1
0040100F |. 8B4D 08 MOV ECX,DWORD PTR SS:[ARG.1]00401012 |. 39C8 CMPEAX,ECX00401014 |. B8 00000000 MOV EAX,0
00401019 |. 0F9CC0 SETLAL0040101C |. 83F8 00 CMP EAX,0
0040101F |. 0F84 51010000 JE 00401176t<3
00401025 |. 8B45 08 MOV EAX,DWORD PTR SS:[ARG.1]00401028 |. 83F8 03 CMP EAX,3
0040102B |. B8 00000000 MOV EAX,0
00401030 |. 0F9CC0 SETLAL00401033 |. 83F8 00 CMP EAX,0
00401036 |. 0F84 5D000000 JE 00401099
1-_0040103C |. B8 01000000 MOV EAX,1
00401041 |. 8B4D 0C MOV ECX,DWORD PTR SS:[ARG.2]00401044 |. 29C8 SUBEAX,ECX
main(-86,0,a+1)00401046 |. 8B4D 10 MOV ECX,DWORD PTR SS:[ARG.3]00401049 |. 41 INCECX0040104A |. 51 PUSH ECX ;/Arg3
0040104B |. B9 00000000 MOV ECX,0 ;|
00401050 |. 51 PUSH ECX ;|Arg2 => 0
00401051 |. B9 AAFFFFFF MOV ECX,-56 ;|
00401056 |. 51 PUSH ECX ;|Arg1 => -56
00401057 |. 8945 FC MOV DWORD PTR SS:[LOCAL.1],EAX ;|
0040105A |. E8 A1FFFFFF CALL 00401000 ;\a.00401000 main(-86,0,a+1)
0040105F |. 83C4 0C ADD ESP,0Cmain(-87,1-_, main(-86,0,a+1)+a)00401062 |. 8B4D 10 MOV ECX,DWORD PTR SS:[ARG.3]00401065 |. 01C1 ADDECX,EAX00401067 |. 51 PUSH ECX ;/Arg3
00401068 |. 8B45 FC MOV EAX,DWORD PTR SS:[LOCAL.1] ;|
0040106B |. 50 PUSH EAX ;|Arg2 => [LOCAL.1]
0040106C |. B8 A9FFFFFF MOV EAX,-57 ;|
00401071 |. 50 PUSH EAX ;|Arg1 => -57
00401072 |. E8 89FFFFFF CALL 00401000 ;\a.00401000 main(-87,1-_, main(-86,0,a+1)+a)
00401077 |. 83C4 0C ADD ESP,0Cmain(-79,-13,a+main(-87,1-_, main(-86,0,a+1)+a))0040107A |. 8B4D 10 MOV ECX,DWORD PTR SS:[ARG.3]0040107D |. 01C1 ADDECX,EAX0040107F |. 51 PUSH ECX ;/Arg3
00401080 |. B8 F3FFFFFF MOV EAX,-0D ;|
00401085 |. 50 PUSH EAX ;|Arg2 => -0D
00401086 |. B8 B1FFFFFF MOV EAX,-4F ;|
0040108B |. 50 PUSH EAX ;|Arg1 => -4F
0040108C |. E8 6FFFFFFF CALL 00401000 ;\a.00401000 main(-79,-13,a+main(-87,1-_, main(-86,0,a+1)+a))
00401091 |. 83C4 0C ADD ESP,0C
00401094 |. E9 0A000000 JMP 004010A3
00401099 |> B8 01000000 MOV EAX,1
0040109E |. E9 00000000 JMP 004010A3t<_004010A3 |> 8B45 08 MOV EAX,DWORD PTR SS:[ARG.1]004010A6 |. 8B4D 0C MOV ECX,DWORD PTR SS:[ARG.2]004010A9 |. 39C8 CMPEAX,ECX004010AB |. B8 00000000 MOV EAX,0
004010B0 |. 0F9CC0 SETLAL004010B3 |. 83F8 00 CMP EAX,0
004010B6 |. 0F84 1A000000 JE 004010D6main(t+1,_,a)004010BC |. 8B45 08 MOV EAX,DWORD PTR SS:[ARG.1]004010BF |. 40 INCEAX004010C0 |. 8B4D 10 MOV ECX,DWORD PTR SS:[ARG.3]004010C3 |. 51 PUSH ECX ;/Arg3 => [ARG.3]
004010C4 |. 8B4D 0C MOV ECX,DWORD PTR SS:[ARG.2] ;|
004010C7 |. 51 PUSH ECX ;|Arg2 => [ARG.2]
004010C8 |. 50 PUSH EAX ;|Arg1
004010C9 |. E8 32FFFFFF CALL 00401000 ;\a.00401000
004010CE |. 83C4 0C ADD ESP,0C
004010D1 |. E9 0A000000 JMP 004010E0
004010D6 |> B8 03000000 MOV EAX,3
004010DB |. E9 00000000 JMP 004010E0main(-94,-27+t,a)004010E0 |> 8B45 08 MOV EAX,DWORD PTR SS:[ARG.1]004010E3 |. 83C0 E5 ADDEAX,-1B004010E6 |. 8B4D 10 MOV ECX,DWORD PTR SS:[ARG.3]004010E9 |. 51 PUSH ECX ;/Arg3 => [ARG.3]
004010EA |. 50 PUSH EAX ;|Arg2
004010EB |. B8 A2FFFFFF MOV EAX,-5E ;|
004010F0 |. 50 PUSH EAX ;|Arg1 => -5E
004010F1 |. E8 0AFFFFFF CALL 00401000 ;\a.00401000 main(-94,-27+t,a)&&t==2
004010F6 |. 83C4 0C ADD ESP,0C
004010F9 |. 83F8 00 CMP EAX,0
004010FC |. 0F84 13000000 JE 00401115t==2
00401102 |. 8B45 08 MOV EAX,DWORD PTR SS:[ARG.1]00401105 |. 83F8 02 CMP EAX,2
00401108 |. 0F85 07000000 JNE 00401115
0040110E |. B8 01000000 MOV EAX,1
00401113 |. EB 05 JMP SHORT 0040111A
00401115 |> B8 00000000 MOV EAX,0
0040111A |> 83F8 00 CMP EAX,0
0040111D |. 0F84 44000000 JE 00401167_<13
00401123 |. 8B45 0C MOV EAX,DWORD PTR SS:[ARG.2]00401126 |. 83F8 0D CMP EAX,0D
00401129 |. B8 00000000 MOV EAX,0
0040112E |. 0F9CC0 SETLAL00401131 |. 83F8 00 CMP EAX,0
00401134 |. 0F84 1E000000 JE 00401158main(2,_+1,"%s %d %d\n")0040113A |. 8B45 0C MOV EAX,DWORD PTR SS:[ARG.2]0040113D |. 40 INCEAX0040113E |. B9 00204000 MOV ECX,OFFSET 00402000 ;ASCII "%s %d %d"
00401143 |. 51 PUSH ECX ;/Arg3 => ASCII "%s %d %d"
00401144 |. 50 PUSH EAX ;|Arg2
00401145 |. B8 02000000 MOV EAX,2 ;|
0040114A |. 50 PUSH EAX ;|Arg1 => 2
0040114B |. E8 B0FEFFFF CALL 00401000 ;\a.00401000 main(2,_+1,"%s %d %d\n")
00401150 |. 83C4 0C ADD ESP,0C
00401153 |. E9 0A000000 JMP 00401162
00401158 |> B8 09000000 MOV EAX,9
0040115D |. E9 00000000 JMP 00401162
00401162 |> E9 0A000000 JMP 00401171
00401167 |> B8 10000000 MOV EAX,10
0040116C |. E9 00000000 JMP 00401171
00401171 |> E9 87010000 JMP 004012FDt<0
00401176 |> 8B45 08 MOV EAX,DWORD PTR SS:[ARG.1]00401179 |. 83F8 00 CMP EAX,0
0040117C |. B8 00000000 MOV EAX,0
00401181 |. 0F9CC0 SETLAL00401184 |. 83F8 00 CMP EAX,0
00401187 |. 0F84 D4000000 JE 00401261t<-72
0040118D |. 8B45 08 MOV EAX,DWORD PTR SS:[ARG.1]00401190 |. 83F8 B8 CMP EAX,-48
00401193 |. B8 00000000 MOV EAX,0
00401198 |. 0F9CC0 SETLAL0040119B |. 83F8 00 CMP EAX,0
0040119E |. 0F84 1B000000 JE 004011BFmain(_,t,strText)004011A4 |. B8 0A204000 MOV EAX,OFFSET 0040200A ;ASCII "@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"...
004011A9 |. 50 PUSH EAX ;/Arg3 => ASCII "@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".
004011AA |. 8B45 08 MOV EAX,DWORD PTR SS:[ARG.1] ;|
004011AD |. 50 PUSH EAX ;|Arg2 => [ARG.1]
004011AE |. 8B45 0C MOV EAX,DWORD PTR SS:[ARG.2] ;|
004011B1 |. 50 PUSH EAX ;|Arg1 => [ARG.2]
004011B2 |. E8 49FEFFFF CALL 00401000 ;\a.00401000 main(_,t, "@n'+,#'/*{}w+/w#cdnr/+,{}r/*de}+
004011B7 |. 83C4 0C ADD ESP,0C
004011BA |. E9 9D000000 JMP 0040125Ct<-50
004011BF |> 8B45 08 MOV EAX,DWORD PTR SS:[ARG.1]004011C2 |. 83F8 CE CMP EAX,-32
004011C5 |. B8 00000000 MOV EAX,0
004011CA |. 0F9CC0 SETLAL004011CD |. 83F8 00 CMP EAX,0
004011D0 |. 0F84 54000000 JE 0040122A_==*a?004011D6 |. 8B45 10 MOV EAX,DWORD PTR SS:[ARG.3]004011D9 |. 8B4D 0C MOV ECX,DWORD PTR SS:[ARG.2]004011DC |. 0FBE10 MOVSX EDX,BYTE PTR DS:[EAX]004011DF |. 39D1 CMPECX,EDX004011E1 |. B8 00000000 MOV EAX,0
004011E6 |. 0F94C0 SETEAL004011E9 |. 83F8 00 CMP EAX,0
004011EC |. 0F84 17000000 JE 00401209putchar(31[a])004011F2 |. 8B45 10 MOV EAX,DWORD PTR SS:[ARG.3]004011F5 |. 83C0 1F ADDEAX,1F004011F8 |. 0FBE08 MOVSX ECX,BYTE PTR DS:[EAX]004011FB |. 51 PUSH ECX ;/c
004011FC |. E8 AF020000 CALL <JMP.&msvcrt.putchar> ;\MSVCRT.putchar
00401201 |. 83C4 04 ADD ESP,4
00401204 |. E9 1C000000 JMP 00401225main(-65,_,a+1)00401209 |> 8B45 10 MOV EAX,DWORD PTR SS:[ARG.3]0040120C |. 40 INCEAX0040120D |. 50 PUSH EAX ;/Arg3
0040120E |. 8B45 0C MOV EAX,DWORD PTR SS:[ARG.2] ;|
00401211 |. 50 PUSH EAX ;|Arg2 => [ARG.2]
00401212 |. B8 BFFFFFFF MOV EAX,-41 ;|
00401217 |. 50 PUSH EAX ;|Arg1 => -41
00401218 |. E8 E3FDFFFF CALL 00401000 ;\a.00401000 main(-65,_,a+1)
0040121D |. 83C4 0C ADD ESP,0C
00401220 |. E9 00000000 JMP 00401225
00401225 |> E9 2D000000 JMP 00401257main((*a=='/')+t,_,a+1)0040122A |> 8B45 10 MOV EAX,DWORD PTR SS:[ARG.3]0040122D |. 0FBE08 MOVSX ECX,BYTE PTR DS:[EAX]00401230 |. 83F9 2F CMP ECX,2F (*a=='/')00401233 |. B8 00000000 MOV EAX,0
00401238 |. 0F94C0 SETEAL0040123B |. 8B4D 08 MOV ECX,DWORD PTR SS:[ARG.1]0040123E |. 01C8 ADD EAX,ECX (*a=='/')+t00401240 |. 8B4D 10 MOV ECX,DWORD PTR SS:[ARG.3]00401243 |. 41 INC ECX a+1
00401244 |. 51 PUSH ECX ;/Arg3
00401245 |. 8B4D 0C MOV ECX,DWORD PTR SS:[ARG.2] ;|
00401248 |. 51 PUSH ECX ;|Arg2 => [ARG.2]
00401249 |. 50 PUSH EAX ;|Arg1
0040124A |. E8 B1FDFFFF CALL 00401000 ;\a.00401000
0040124F |. 83C4 0C ADD ESP,0C
00401252 |. E9 00000000 JMP 00401257
00401257 |> E9 00000000 JMP 0040125C
0040125C |> E9 97000000 JMP 004012F8
0<t00401261 |> B8 00000000 MOV EAX,0
00401266 |. 8B4D 08 MOV ECX,DWORD PTR SS:[ARG.1]00401269 |. 39C8 CMPEAX,ECX0040126B |. B8 00000000 MOV EAX,0
00401270 |. 0F9CC0 SETLAL00401273 |. 83F8 00 CMP EAX,0
00401276 |. 0F84 1F000000 JE 0040129Bmain(2,2,"%s")0040127C |. B8 A2214000 MOV EAX,OFFSET 004021A2 ;ASCII "%s"
00401281 |. 50 PUSH EAX ;/Arg3 => ASCII "%s"
00401282 |. B8 02000000 MOV EAX,2 ;|
00401287 |. 50 PUSH EAX ;|Arg2 => 2
00401288 |. B8 02000000 MOV EAX,2 ;|
0040128D |. 50 PUSH EAX ;|Arg1 => 2
0040128E |. E8 6DFDFFFF CALL 00401000 ;\a.00401000 main(2,2,"%s")
00401293 |. 83C4 0C ADD ESP,0C
00401296 |. E9 58000000 JMP 004012F3*a=='/'
0040129B |> 8B45 10 MOV EAX,DWORD PTR SS:[ARG.3]0040129E |. 0FBE08 MOVSX ECX,BYTE PTR DS:[EAX]004012A1 |. 83F9 2F CMPECX,2F004012A4 |. 0F84 3F000000 JE 004012E9main(-61,*a, "!ek;dc i@bK'(q)-[w]*%n+r3#l,{}:\nuwloca-O;m .vpbks,fxntdCeghiry")004012AA |. 8B45 10 MOV EAX,DWORD PTR SS:[ARG.3]004012AD |. B9 A5214000 MOV ECX,OFFSET 004021A5 ;ASCII "!ek;dc i@bK'(q)-[w]*%n+r3#l,{}: \nuwloca-O;m .vpbks,fxntdCeghiry"
004012B2 |. 51 PUSH ECX ;/Arg3 => ASCII "!ek;dc i@bK'(q)-[w]*%n+r3#l,{}:uwloca-O;m .vpbks,fxntdCeghiry"
004012B3 |. 0FBE08 MOVSX ECX,BYTE PTR DS:[EAX] ;|
004012B6 |. 51 PUSH ECX ;|Arg2
004012B7 |. B8 C3FFFFFF MOV EAX,-3D ;|
004012BC |. 50 PUSH EAX ;|Arg1 => -3D
004012BD |. E8 3EFDFFFF CALL 00401000 ;\a.00401000 main(-61,*a, "!ek;dc i@bK'(q)-[w]*%n+r3#l,{}:\nuwloca-O;m .vpbks,fxntdCeghiry"
004012C2 |. 83C4 0C ADD ESP,0Cmain(0,main(-61,*a, "!ek;dc i@bK'(q)-[w]*%n+r3#l,{}:\nuwloca-O;m .vpbks,fxntdCeghiry"),a+1)004012C5 |. 8B4D 10 MOV ECX,DWORD PTR SS:[ARG.3]004012C8 |. 41 INCECX004012C9 |. 51 PUSH ECX ;/Arg3
004012CA |. 50 PUSH EAX ;|Arg2
004012CB |. B8 00000000 MOV EAX,0 ;|
004012D0 |. 50 PUSH EAX ;|Arg1 => 0
004012D1 |. E8 2AFDFFFF CALL 00401000 ;\a.00401000 main(0,main(-61,*a, "!ek;dc i@bK'(q)-[w]*%n+r3#l,{}:\nu
004012D6 |. 83C4 0C ADD ESP,0C
004012D9 |. 83F8 00 CMP EAX,0
004012DC |. 0F85 07000000 JNE 004012E9
004012E2 |. B8 00000000 MOV EAX,0
004012E7 |. EB 05 JMP SHORT 004012EE
004012E9 |> B8 01000000 MOV EAX,1
004012EE |> \E9 00000000 JMP 004012F3
004012F3 |> E9 00000000 JMP 004012F8
004012F8 |> E9 00000000 JMP 004012FD
004012FD |> C9 LEAVE
004012FE \. C3 RETN
5 源代码断句
源码基于?/,/操作进行格式重排.用汇编代码辅助判断断句是否与原码执行一致。
为方便理解将二个字符串用宏替换。第一个是明文,第二个字符串是用来加密的密钥。
#include <stdio.h>
#define strText "@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' ')# \
}'+}##(!!/"
#define strEnc "!ek;dc i@bK'(q)-[w]*%n+r3#l,{}:\nuwloca-O;m .vpbks,fxntdCeghiry"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,strText)
:
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,strEnc),a+1);
}
6 用C语言的if-then-else语句解析
#include <stdio.h>
#define strText "@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' ')# \
}'+}##(!!/"
#define strEnc "!ek;dc i@bK'(q)-[w]*%n+r3#l,{}:\nuwloca-O;m .vpbks,fxntdCeghiry"main(t,_,a)char *a;
{if ((!0)<t)
{if (t<3)
{
main(-79,-13,a+main(-87,1-_,main(-86,0,a+1)+a));
}else{1;
}if (t<_)
{
main(t+1,_,a);
}else{3;
}if (main(-94,-27+t,a) && t==2)
{if (_<13)
{return main(2,_+1,"%s %d %d\n");
}else{return 9;
}
}else{return 16;
}
}else{if (t<0)
{if (t<-72)
{returnmain(_,t,strText );
}else{if (t<-50)
{if (_==(*a))
{return putchar(31[a]);
}else{return main(-65,_,a+1);
}
}else{return main((*a=='/')+t,_,a+1);
}
}
}else{if (0<t)
{return main(2,2,"%s");
}else{return (*a=='/')||main(0,main(-61,*a,strEnc ),a+1);
}
}
}
}
7 源码分析
7.1)!0为常数1
7.2)main(-79,-13,a+main(-87,1-_,main(-86,0,a+1)+a));
这语句为嵌套,可以分解为
int m1=main(-86,0,a+1);int m2=main(-87,1-_,m1+a);
main(-79,-13,a+m2);
7.3)A,B语句中的逗号(,),表示执行完A,继续执行B
7.4)main(-94,-27+t,a) && t==2?A:B这语句可以分解成
int m3=main(-94,-27+t,a);
if(m3&& t==2)A;
else B;
7.5)return *a=='/'||main(0,main(-61,*a,strEnc),a+1);这语句可以分解成
if(*a=='/')
{
return 1;
}else
{
return main(0,main(-61,*a,strEnc),a+1);
}
因为运行到当前分支t=0,这其实是递归函数
7.6)putchar(31[a]),注意31[a],中括号[]代表C语言的数组,因为a[31]等同与*(a+31),31[a]等同与*(31+a),所以31[a]等同于a[31]。
8 整理代码
8.1)根据if-then-else源码,整理代码前面根据t的伪代码
if(t>1) Do2();
else if(t<0) DoN();
else if(t>0) Do1(); //满足t<=1&&t>=0&&t>0的t值只能为1
else Do0(); //以上都不满足的t只能为0
8.2)按t从大到小整理伪代码
if(t>1) Do2();
else if(t==1)Do1();
else if(t==0)Do0();
else DoN();
8.3)按t从大到小整理伪代码整理源码
#include <stdio.h>
#define strText "@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' ')# \
}'+}##(!!/"
#define strEnc "!ek;dc i@bK'(q)-[w]*%n+r3#l,{}:\nuwloca-O;m .vpbks,fxntdCeghiry"
main(t,_,a)
char *a;
{
if (t>1)
{
if (t<3)
{
main(-79,-13,a+main(-87,1-_,main(-86,0,a+1)+a));
}
else
{
1;
}
if (t<_)
{
main(t+1,_,a);
}
else
{
3;
}
if (main(-94,-27+t,a) && t==2)
{
if (_<13)
{
return main(2,_+1,"%s %d %d\n");
}
else
{
return 9;
}
}
else
{
return 16;
}
}
else if(t==1)
{
return main(2,2,"%s");
}else if(t==0)
{
return (*a=='/')||main(0,main(-61,*a,strEnc),a+1);
}else if(t>=-50)
{
return main((*a=='/')+t,_,a+1);
}else if(t>=-72)
{
if (_==(*a))
{
return putchar(31[a]);
}
else
{
return main(-65,_,a+1);
}
}else
{
return main(_,t,strText );
}
}
9 输出分析
源码输出语句只有一句putchar(31[a]),此时t应满足-50>t>=-72。源码递归调用main(-65,_,a+1)直到(_==*a),然后打印解密后的31[a]字符。
用来解密的密钥如下
#define strEnc "!ek;dc i@bK'(q)-[w]*%n+r3#l,{}:\nuwloca-O;m .vpbks,fxntdCeghiry"
所以序号为1字符‘e'对应的原字符’u'序号为32=1+31,序号为2字符'k'的加密前原字符为'w',序号为33=2+31。注意'!'(序号为0)对应于加密前的换行‘\n'序号31。
用这种解密文本
"@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' ')# \
}'+}##(!!/"
解密后的原文如下,
"On the /first/second/third/fourth/fifth/sixth/seventh/eigth/ninth/tenth/eleventh/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.
"
代码中字符'/'没有加密,用来分隔之子字符串,比加first,second。
改写不加密的源码,为避免换行'\n'中有字符'\',将换行符用'!',输出字符中对'!'当成换行处理。
#include <stdio.h>
#define strDeText "On the /first/second/third/fourth/fifth/sixth/seventh/eigth/ninth/tenth/eleventh/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.!!/"main(t,_,a)char *a;
{if (t>1)
{if (t<3)
{
main(-79,-13,a+main(-87,1-_,main(-86,0,a+1)+a));
}else{1;
}if (t<_)
{
main(t+1,_,a);
}else{3;
}if (main(-94,-27+t,a) && t==2)
{if (_<13)
{return main(2,_+1,"%s %d %d\n");
}else{return 9;
}
}else{return 16;
}
}else if(t==1)
{return main(2,2,"%s");
}else if(t==0)
{return (*a=='/')||main(0,main(-61,*a,""),a+1);
}else if(t>=-50)
{return main((*a=='/')+t,_,a+1);
}else if(t>=-72)
{if(_=='!')_='\n';returnputchar(_);
}else{returnmain(_,t,strDeText );
}
}
为了更好理解原代码,将'/'分隔的子字符用一个字母表示。
比如"first"用字符'a'代替,"second"用'b'代替,等等。简化代码如下
#include <stdio.h>
#define strDeText "On /a/b/c/d/e/f/g/h/i/j/k/l/ day /L,/K,/J,/I,/H,/G,/F,/E,/D,/C,/B,/A.!/"
main(t,_,a)
char *a;
{
if (t>1)
{
if (t<3)
{
main(-79,-13,a+main(-87,1-_,main(-86,0,a+1)+a));
}
else
{
1;
}
if (t<_)
{
main(t+1,_,a);
}
else
{
3;
}
if (main(-94,-27+t,a) && t==2)
{
if (_<13)
{
return main(2,_+1,"%s %d %d\n");
}
else
{
return 9;
}
}
else
{
return 16;
}
}
else if(t==1)
{
return main(2,2,"%s");
}else if(t==0)
{
return (*a=='/')||main(0,main(-61,*a,""),a+1);
}else if(t>=-50)
{
return main((*a=='/')+t,_,a+1);
}else if(t>=-72)
{
if(_=='!')_='\n';
return putchar(_);
}else
{//t<-72
return main(_,t,strDeText );
}
}
运行程序输出如下:
On a day A.
On b day B,A.
On c day C,B,A.
On d day D,C,B,A.
On e day E,D,C,B,A.
On f day F,E,D,C,B,A.
On g day G,F,E,D,C,B,A.
On h day H,G,F,E,D,C,B,A.
On i day I,H,G,F,E,D,C,B,A.
On j day J,I,H,G,F,E,D,C,B,A.
On k day K,J,I,H,G,F,E,D,C,B,A.
On l day L,K,J,I,H,G,F,E,D,C,B,A.
改写t==0时用递归方式输出字符串为正常调用函数,并注意到t<-72时,交换t和_且把a固定为strDeText递归调用main.
#include <stdio.h>
#define strDeText "On /a/b/c/d/e/f/g/h/i/j/k/l/ day /L,/K,/J,/I,/H,/G,/F,/E,/D,/C,/B,/A.!/"
int funprint(t,_,a)
char *a;
{
while(*a!='/')
{
char c=*a;
if(c=='!')c='\n';
putchar(c);
a++;
}
return 1;
}
main(t,_,a)
char *a;
{
if (t>1)
{
if (t<3)
{
int m1=main(0,-86,strDeText);
int m2=main(1-_,-87,strDeText);
main(-13,-79,strDeText);
}
else
{
1;
}
if (t<_)
{
main(t+1,_,a);
}
else
{
3;
}
if (main(-27+t,-94,strDeText) && t==2)
{
if (_<13)
{
return main(2,_+1,"%s %d %d\n");
}
else
{
return 9;
}
}
else
{
return 16;
}
}
else if(t==1)
{
return main(2,2,"%s");
}else if(t==0)
{
return funprint(t,_,a);
}else if(t>=-50)
{//
return main((*a=='/')+t,_,a+1);
}else if(t>=-72)
{
if(_=='!')_='\n';
return putchar(_);
}else
{
return main(_,t,strDeText );
}
}
代码比较清晰了,可以注意到int m1=main(0,-86,strDeText)输出"On ",
int m2=main(1-_,-87,strDeText)输出'a'或者'b'或者’c'等等,
main(-13,-79,strDeText)输出' day ',可以明白对运行t>=-50这个分支递归调用main,此时t表示'/'的个数。
继续改写代码,将以上三个递归改成函数调用
1 #include <stdio.h>
2
3 #define strDeText "On /a/b/c/d/e/f/g/h/i/j/k/l/ day /L,/K,/J,/I,/H,/G,/F,/E,/D,/C,/B,/A.!/"
4
5 intfunprint(t,_,a)6 char *a;7 {8 while(*a!='/')9 {10 char c=*a;11 if(c=='!')c='\n';12 putchar(c);13 a++;14 }15 return 1;16 }17
18 intfunOut(t,_,a)19 char *a;20 {21 inti;22 for(i=t;i<0;i++)23 {24 while(*a!='/')25 {26 a++;27 }28 a++;29 }30 returnfunprint(t,_,a);31 }32
33 main(t,_,a)34 char *a;35 {36 if (t>1)37 {38 if (t<3)39 {40 int m1=funOut(0,-86,strDeText);41 int m2=funOut(1-_,-87,strDeText);42 funOut(-13,-79,strDeText);43 }44 else
45 {46 1;47 }48 if (t<_)49 {50 main(t+1,_,a);51 }52 else
53 {54 3;55 }56
57 if (funOut(-27+t,-94,strDeText) && t==2)58 {59 if (_<13)60 {61 return main(2,_+1,"%s %d %d\n");62 }63 else
64 {65 return 9;66 }67 }68 else
69 {70 return 16;71 }72 }73 else if(t==1)74 {75 return main(2,2,"%s");76 }else if(t==0)77 {78 returnfunprint(t,_,a);79 }else if(t>=-50)80 {81 return main((*a=='/')+t,_,a+1);82 }else if(t>=-72)83 {84 if(_=='!')_='\n';85 returnputchar(_);86 }else
87 {88 returnmain(_,t,strDeText );89 }90
91 }
程序从t=1开始运行,递归调用t=2,_=2,打印完"On
a day A."第一句后main(2,_+1,"%s %d %d\n")递归调用main,将_值加1变成3,
运行
int m1=funOut(0,-86,strDeText);int m2=funOut(1-_,-87,strDeText);
funOut(-13,-79,strDeText);
打印"On
b day
",因为t=2,_=3,递归调用main(t+1,_,a),此时t=3,_=3,返回后调用funOut(-27+t,-94,strDeText)打印出"B,A.",
继续调用main(2,_+1,"%s
%d
%d\n")将_值加1变成4,...,直到_=13完成输出"L,K,J,I,H,G,F,E,D,C,B,A."
明白这点后,将t>1的递归改成函数调用
#include <stdio.h>
#define strDeText "On /a/b/c/d/e/f/g/h/i/j/k/l/ day /L,/K,/J,/I,/H,/G,/F,/E,/D,/C,/B,/A.!/"
intfunprint(t,_,a)char *a;
{while(*a!='/')
{char c=*a;if(c=='!')c='\n';
putchar(c);
a++;
}return 1;
}intfunOut(t,_,a)char *a;
{inti;for(i=t;i<0;i++)
{while(*a!='/')
{
a++;
}
a++;
}returnfunprint(t,_,a);
}
main(t,_,a)char *a;
{if (t>1)
{inti,j;for(;_<13;_++)
{int m1=funOut(0,-86,strDeText);int m2=funOut(1-_,-87,strDeText);
funOut(-13,-79,strDeText);
i=_;while(i>=t)
{
funOut(-27+i,-94,strDeText);
i--;
}
}
}else if(t==1)
{return main(2,2,"%s");
}else if(t==0)
{returnfunprint(t,_,a);
}else if(t>=-50)
{return main((*a=='/')+t,_,a+1);
}else if(t>=-72)
{if(_=='!')_='\n';returnputchar(_);
}else{returnmain(_,t,strDeText );
}
}
最后去掉没用的代码,结构化改写原码,简单的逻辑打印出结果
#include <stdio.h>
//#define strDeText "On /a/b/c/d/e/f/g/h/i/j/k/l/ day /L,/K,/J,/I,/H,/G,/F,/E,/D,/C,/B,/A.!/"
#define strDeText "On the /first/second/third/fourth/fifth/sixth/seventh/eigth/ninth/tenth/eleventh/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.!!/"int fun0Print(char *a)
{while(*a!='/')
{char c=*a;if(c=='!')c='\n';
putchar(c);
a++;
}return 1;
}void funPrint(intk)
{char *s=strDeText;inti;for(i=k;i<0;i++)
{while(*s!='/')
{
s++;
}
s++;
}
fun0Print(s);
}voidfunDisp()
{int_,m;inti;for(_=2;_<=13;_++)
{
funPrint(0); //输出"On "
funPrint(1-_); //输出" a "or" b "or" c "or" d "or ....
funPrint(-13); //输出" day "
for(m=_;m>=2;m--)
{
funPrint(-27+m); //输出" L,/K,/J,/I,/H,/G,/F,/E,/D,/C,/B,/A.!"
}
}
}
main(int t,int _,char*a)
{
funDisp();
}