程序在我们的日常生活中扮演了重要角色,小到吃饭刷卡,达到发射火箭,似乎无所不能。那么问题来了,有能输出本身源代码的程序吗?
这似乎是个死循环,就“如要理解递归,就要理解递归”一样。然而,如果我们采取一些巧妙的方法,还是有方法实现的,并且实现的方法不止一种。人们把这种程序称为“Quine”。下面是一个使用C++语言的Quine。
1
2
3
|
#include <stdio.h>
char
*
s
=
"#include <stdio.h>%cchar*s=%c%s%c;%cmain(){printf(s,10,34,s,34,10,10);}%c"
;
main
(
)
{
printf
(
s
,
10
,
34
,
s
,
34
,
10
,
10
)
;
}
|
将换行符和引号等用对应的字符编码替换,巧妙地避免使用“\”引起死循环。
早在19世纪六十年代 爱丁堡大学的 Hamish Dewar就已写出第一个Quine程序
当时的程序是这样的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
%BEGIN
!THIS IS A SELF-REPRODUCING PROGRAM
%ROUTINESPEC R
R
PRINT SYMBOL(39)
R
PRINT SYMBOL(39)
NEWLINE
%CAPTION %END~
%CAPTION %ENDOFPROGRAM~
%ROUTINE R
%PRINTTEXT '
%BEGIN
!THIS IS A SELF-REPRODUCING PROGRAM
%ROUTINESPEC R
R
PRINT SYMBOL(39)
R
PRINT SYMBOL(39)
NEWLINE
%CAPTION %END~
%CAPTION %ENDOFPROGRAM~
%ROUTINE R
%PRINTTEXT '
%END
%ENDOFPROGRAM
|
据说AGPL协议中的关于下载源的规定的灵感就来自Quine
我们也可以换一种思路写Quine,我们可以利用编译器中的预定义宏“__FILE__”
1
2
3
4
5
6
7
8
9
10
|
#include <stdio.h>
char
buff
[
80
]
;
main
(
)
{
FILE
*
fp
;
fp
=
fopen
(
__FILE__
,
"r"
)
;
while
(
!
feof
(
fp
)
)
{
printf
(
"%s"
,
fgets
(
buff
,
79
,
fp
)
)
;
}
fclose
(
fp
)
;
}
|
我们还可以通过各种不同的语言来写
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
public
class
Quine
{
public
static
void
main
(
String
[
]
args
)
{
char
q
=
34
;
String
[
]
l
=
{
" "
,
"=============<<<<<<<< C++ Code >>>>>>>>============="
,
"#include <iostream>"
,
"#include <string>"
,
"using namespace std;"
,
""
,
"int main(int argc, char* argv[])"
,
"{"
,
" char q = 34;"
,
" string l[] = {"
,
" };"
,
" for(int i = 20; i <= 25; i++)"
,
" cout << l[i] << endl;"
,
" for(int i = 0; i <= 34; i++)"
,
" cout << l[0] + q + l[i] + q + ',' << endl;"
,
" for(int i = 26; i <= 34; i++)"
,
" cout << l[i] << endl;"
,
" return 0;"
,
"}"
,
"=============<<<<<<<< Java Code >>>>>>>>=========="
,
"public class Quine"
,
"{"
,
" public static void main( String[] args )"
,
" {"
,
" char q = 34;"
,
" String[] l = {"
,
" };"
,
" for(int i = 2; i <= 9; i++)"
,
" System.out.println(l[i]);"
,
" for(int i = 0; i < l.length; i++)"
,
" System.out.println( l[0] + q + l[i] + q + ',' );"
,
" for(int i = 10; i <= 18; i++))"
,
" System.out.println(l[i]);"
,
" }"
,
"}"
,
}
;
for
(
int
i
=
2
;
i
<=
9
;
i
++
)
System
.
out
.
println
(
l
[
i
]
)
;
for
(
int
i
=
0
;
i
<
l
.
length
;
i
++
)
System
.
out
.
println
(
l
[
0
]
+
q
+
l
[
i
]
+
q
+
','
)
;
for
(
int
i
=
10
;
i
<=
18
;
i
++
)
System
.
out
.
println
(
l
[
i
]
)
;
}
}
|
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
#include <iostream>
#include <string>
using
namespace
std
;
int
main
(
int
argc
,
char
*
argv
[
]
)
{
char
q
=
34
;
string
l
[
]
=
{
" "
,
"=============<<<<<<<< C++ Code >>>>>>>>============="
,
"#include <iostream>"
,
"#include <string>"
,
"using namespace std;"
,
""
,
"int main(int argc, char* argv[])"
,
"{"
,
" char q = 34;"
,
" string l[] = {"
,
" };"
,
" for(int i = 20; i <= 25; i++)"
,
" cout << l[i] << endl;"
,
" for(int i = 0; i <= 34; i++)"
,
" cout << l[0] + q + l[i] + q + ',' << endl;"
,
" for(int i = 26; i <= 34; i++)"
,
" cout << l[i] << endl;"
,
" return 0;"
,
"}"
,
"=============<<<<<<<< Java Code >>>>>>>>============="
,
"public class Quine"
,
"{"
,
" public static void main(String[] args)"
,
" {"
,
" char q = 34;"
,
" String[] l = {"
,
" };"
,
" for(int i = 2; i <= 9; i++)"
,
" System.out.println( l[i] );"
,
" for(int i = 0; i < l.length; i++)"
,
" System.out.println(l[0] + q + l[i] + q + ',');"
,
" for(int i = 10; i <= 18; i++)"
,
" System.out.println(l[i]);"
,
" }"
,
"}"
,
}
;
for
(
int
i
=
20
;
i
<=
25
;
i
++
)
cout
<<
l
[
i
]
<<
endl
;
for
(
int
i
=
0
;
i
<=
34
;
i
++
)
cout
<<
l
[
0
]
+
q
+
l
[
i
]
+
q
+
','
<<
endl
;
for
(
int
i
=
26
;
i
<=
34
;
i
++
)
cout
<<
l
[
i
]
<<
endl
;
return
0
;
}
|
它们分别输出对方的代码。
不仅是两种语言,我们还可以把50种不同的编程语言构成一个循环。
他叫Quine Relay
它一开始是一段Ruby代码,运行后生成Scala代码,后者运行后生成Scheme代码……最后又回到最初的Ruby代码。一边执行一边能画出一条正在吞食自己尾巴的蛇,刚好表示了循环。
项目地址:github.com/mame/quine-relay
更多Quine代码:www.nyx.net/~gthompso/
部分资料来自维基百科:en.wikipedia.org/wiki/Quine_(computing)
They Said "All we are is sinking endless."
原文地址:http://ozem.pw/archives/798