如何编写自我复制代码(在exec上打印源代码)?

时间:2008-09-19 21:20:04

标签: programming-languages quine

我已经看到很多基于C / C ++的解决方案,我们必须编写一个程序,在执行时打印自己的源代码。

一些解决方案 -

http://www.cprogramming.com/challenges/solutions/self_print.html

Quine Page solution in many languages

网上还有更多解决方案,每个解决方案都不同。我想知道我们如何处理这样一个问题,解决它的人心中的问题。请给我一些关于这个问题的见解......虽然解释语言中的解决方案如perl,php,ruby等可能很容易......我想知道如何用编译语言设计它......

12 个答案:

答案 0 :(得分:53)

除了作弊¹,编译语言和解释语言之间没有区别。

quines的通用方法非常简单。首先,无论程序是什么样的,在某些时候它必须打印一些东西:

print ...

然而,它应该打印什么?本身。所以它需要打印“print”命令:

print "print ..."

接下来应该打印什么?好吧,在程序增长的同时,它需要打印以“print”开头的字符串:

print "print \"print ...\""

现在程序再次增长,所以还有更多要打印的内容:

print "print \"print \\\"...\\\"\""

等等。 每增加一个代码,就会有更多代码需要打印。 这种方法无处可去, 但它揭示了一个有趣的模式: 字符串“print”“一遍又一遍地重复。 把重复的部分放在一边会很好 变成一个变量:

a = "print \""
print a

然而,该计划刚刚改变, 所以我们需要调整一下:

a = "a = ...\nprint a"
print a

当我们现在尝试填写“......”时, 我们遇到了和以前一样的问题。 最终,我们想写这样的东西:

a = "a = " + (quoted contents of a) + "\nprint a"
print a

但这是不可能的, 因为即使我们有这样的函数quoted()用于引用, 仍然存在我们根据自身定义a的问题:

a = "a = " + quoted(a) + "\nprint a"
print a

所以我们唯一能做的就是将占位符放入a

a = "a = @\nprint a"
print a

这就是全部技巧! 其他任何事情现在都清楚了。 只需更换占位符即可 引用的内容为a

a = "a = @\nprint a"
print a.replace("@", quoted(a))

由于我们更改了代码, 我们需要调整字符串:

a = "a = @\nprint a.replace(\"@\", quoted(a))"
print a.replace("@", quoted(a))

就是这样! 所有语言的所有quines都以这种方式工作 (除了作弊者)。

嗯,你应该确保只更换 第一次出现的占位符。 如果你使用第二名持有人, 你可以避免引用字符串。

但这些都是小问题 而且容易解决。 事实上,quoted()replace()的实现 是各种细节真正不同的唯一细节。


¹使程序读取其源文件

答案 1 :(得分:9)

编写quines有几种不同的策略。显而易见的是只编写打开代码并将其打印出来的代码。但更有趣的是涉及允许自嵌入的语言功能,例如许多语言中的%s风格的printf功能。您必须弄清楚如何嵌入某些内容,以便最终解析为嵌入请求。我怀疑,像回文一样,涉及到很多反复试验。

答案 2 :(得分:2)

你也可以研究Core Wars游戏的运作方式。我认为这是一个很好的例子。

答案 3 :(得分:1)

通常的方法(当你不能作弊*时)是在字符串常量中编写对其源进行编码的东西,然后将该常量打印两次:一次作为字符串文字,一次作为代码。这就解决了“每次我写一行代码时,我都要写另一个来打印出来!”问题

'作弊'包括: - 使用解释语言,只需加载源并打印它 - 0字节长文件,在某些语言中有效,例如C。

答案 4 :(得分:1)

为了好玩,我在Scheme中找到了一个,我感到非常自豪约5分钟,直到我发现之前已被发现。无论如何,对游戏的“规则”进行了一些修改,以便更好地计算Lisp中数据和代码的二元性:不是打印出程序的源代码,而是一个返回自身的S表达式:

((lambda (x) (list x `',x)) '(lambda (x) (list x `',x)))

one on Wikipedia具有相同的概念,但引用机制略有不同(更详细)。我虽然更喜欢我。

答案 5 :(得分:0)

考虑编码以及如何赋予双重含义的一个想法,以便它可以用于输出几种形式的东西。除了程序输出本身之外没有任何规则,这种类型的问题还有限制使得它变得更加困难,空程序是一种解决方案。

答案 6 :(得分:0)

您可以在此处找到相当多的解决方案:http://forums.thedailywtf.com/forums/p/5232/147528.aspx

答案 7 :(得分:0)

实际阅读和打印源代码怎么样?这一点都不难!在PHP中有一个人:

<?php
{
header("Content-Type: text/plain");
    $f=fopen("5.php","r");
    while(!feof($f))
    {
        echo fgetc($f);
    } 
    fclose($f);
}
?>

答案 8 :(得分:0)

在python中,你可以写:

s='c=chr(39);print"s="+c+s+c+";"+s';c=chr(39);print"s="+c+s+c+";"+s

受到这种自我打印伪代码的启发:

Print the following line twice, the second time with quotes.
"Print the following line twice, the second time with quotes."

答案 9 :(得分:0)

我为那些对此

感兴趣的人做了一个AS3示例
var program = "var program = @; function main(){trace(program.replace('@', 

String.fromCharCode(34) + program + String.fromCharCode(34)))} main()"; 
function main(){
   trace(program.replace('@', String.fromCharCode(34) + program + String.fromCharCode(34)))
}
main()

答案 10 :(得分:-1)

在bash中非常简单

触摸测试; chmod oug + x测试; ./test

空文件,空输出

答案 11 :(得分:-2)

在红宝石中:

放入File.read(_ _ FILE _ _)