神奇的C語言輸出12天聖誕節歌詞程式碼

webccaa發表於2024-09-04

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();      
}
      

相關文章