神奇的C语言输出12天圣诞节歌词代码

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 %dn"):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 %dn") 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 %dn") 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 %dn")                    :                         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 %dn");             }             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 %dn");             }             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 %dn");             }             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 %dn");             }             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 %dn");             }             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 %dn"); 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 %dn")递归调用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 %dn")将_值加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();       }       

 

发表评论

相关文章