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 Comments 00401000 /$ 55 PUSH EBP ; a.00401000(guessed Arg1,Arg2,Arg3) 00401001 |. 89E5 MOV EBP,ESP 00401003 |. 81EC 04000000 SUB ESP,4 00401009 |. 90 NOP !0<t 0040100A |. B8 01000000 MOV EAX,1 0040100F |. 8B4D 08 MOV ECX,DWORD PTR SS:[ARG.1] 00401012 |. 39C8 CMP EAX,ECX 00401014 |. B8 00000000 MOV EAX,0 00401019 |. 0F9CC0 SETL AL 0040101C |. 83F8 00 CMP EAX,0 0040101F |. 0F84 51010000 JE 00401176 t<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 SETL AL 00401033 |. 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 SUB EAX,ECX main(-86,0,a+1) 00401046 |. 8B4D 10 MOV ECX,DWORD PTR SS:[ARG.3] 00401049 |. 41 INC ECX 0040104A |. 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,0C main(-87,1-_, main(-86,0,a+1)+a) 00401062 |. 8B4D 10 MOV ECX,DWORD PTR SS:[ARG.3] 00401065 |. 01C1 ADD ECX,EAX 00401067 |. 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,0C main(-79,-13,a+main(-87,1-_, main(-86,0,a+1)+a)) 0040107A |. 8B4D 10 MOV ECX,DWORD PTR SS:[ARG.3] 0040107D |. 01C1 ADD ECX,EAX 0040107F |. 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 004010A3 t<_ 004010A3 |> 8B45 08 MOV EAX,DWORD PTR SS:[ARG.1] 004010A6 |. 8B4D 0C MOV ECX,DWORD PTR SS:[ARG.2] 004010A9 |. 39C8 CMP EAX,ECX 004010AB |. B8 00000000 MOV EAX,0 004010B0 |. 0F9CC0 SETL AL 004010B3 |. 83F8 00 CMP EAX,0 004010B6 |. 0F84 1A000000 JE 004010D6 main(t+1,_,a) 004010BC |. 8B45 08 MOV EAX,DWORD PTR SS:[ARG.1] 004010BF |. 40 INC EAX 004010C0 |. 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 004010E0 main(-94,-27+t,a) 004010E0 |> 8B45 08 MOV EAX,DWORD PTR SS:[ARG.1] 004010E3 |. 83C0 E5 ADD EAX,-1B 004010E6 |. 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 00401115 t==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 SETL AL 00401131 |. 83F8 00 CMP EAX,0 00401134 |. 0F84 1E000000 JE 00401158 main(2,_+1,"%s %d %d\n") 0040113A |. 8B45 0C MOV EAX,DWORD PTR SS:[ARG.2] 0040113D |. 40 INC EAX 0040113E |. 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 004012FD t<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 SETL AL 00401184 |. 83F8 00 CMP EAX,0 00401187 |. 0F84 D4000000 JE 00401261 t<-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 SETL AL 0040119B |. 83F8 00 CMP EAX,0 0040119E |. 0F84 1B000000 JE 004011BF main(_,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 0040125C t<-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 SETL AL 004011CD |. 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 CMP ECX,EDX 004011E1 |. B8 00000000 MOV EAX,0 004011E6 |. 0F94C0 SETE AL 004011E9 |. 83F8 00 CMP EAX,0 004011EC |. 0F84 17000000 JE 00401209 putchar(31[a]) 004011F2 |. 8B45 10 MOV EAX,DWORD PTR SS:[ARG.3] 004011F5 |. 83C0 1F ADD EAX,1F 004011F8 |. 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 00401225 main(-65,_,a+1) 00401209 |> 8B45 10 MOV EAX,DWORD PTR SS:[ARG.3] 0040120C |. 40 INC EAX 0040120D |. 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 00401257 main((*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 SETE AL 0040123B |. 8B4D 08 MOV ECX,DWORD PTR SS:[ARG.1] 0040123E |. 01C8 ADD EAX,ECX (*a=='/')+t 00401240 |. 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<t 00401261 |> B8 00000000 MOV EAX,0 00401266 |. 8B4D 08 MOV ECX,DWORD PTR SS:[ARG.1] 00401269 |. 39C8 CMP EAX,ECX 0040126B |. B8 00000000 MOV EAX,0 00401270 |. 0F9CC0 SETL AL 00401273 |. 83F8 00 CMP EAX,0 00401276 |. 0F84 1F000000 JE 0040129B main(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 CMP ECX,2F 004012A4 |. 0F84 3F000000 JE 004012E9 main(-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,0C main(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 INC ECX 004012C9 |. 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) { return main(_,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'; return putchar(_); }else { return main(_,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 int funprint(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 int funOut(t,_,a) 19 char *a; 20 { 21 int i; 22 for(i=t;i<0;i++) 23 { 24 while(*a!='/') 25 { 26 a++; 27 } 28 a++; 29 } 30 return funprint(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 return funprint(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 return putchar(_); 86 }else 87 { 88 return main(_,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.!/" int funprint(t,_,a) char *a; { while(*a!='/') { char c=*a; if(c=='!')c='\n'; putchar(c); a++; } return 1; } int funOut(t,_,a) char *a; { int i; for(i=t;i<0;i++) { while(*a!='/') { a++; } a++; } return funprint(t,_,a); } main(t,_,a) char *a; { if (t>1) { int i,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) { 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 ); } }
最後去掉沒用的程式碼,結構化改寫原碼,簡單的邏輯列印出結果
#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(int k) { char *s=strDeText; int i; for(i=k;i<0;i++) { while(*s!='/') { s++; } s++; } fun0Print(s); } void funDisp() { int _,m; int i; 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(); }