【问题标题】:How to write a self reproducing code (prints the source on exec)?如何编写自我复制代码(在 exec 上打印源代码)?
【发布时间】:2008-09-19 21:20:03
【问题描述】:

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

一些解决方案--

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

Quine Page solution in many languages

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

【问题讨论】:

    标签: programming-languages quine


    【解决方案1】:

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

    quines 的通用方法非常简单。首先,无论程序看起来如何,在某些时候它都必须打印一些东西:

    打印 ...

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

    打印“打印...”

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

    打印“打印\”打印...\“”

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

    打印"打印\"打印\\\"...\\\"\""

    等等。 每添加一个代码,就会有更多代码要打印。 这种方法行不通, 但它揭示了一个有趣的模式: 字符串 "print \"" 一遍又一遍地重复。 把重复的部分放上去就好了 变成一个变量:

    a = "打印\"" 打印一个

    但是,程序刚刚改变, 所以我们需要调整一个:

    a = "a = ...\n打印一个" 打印一个

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

    a = "a = " + (a 的引用内容) + "\nprint a" 打印一个

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

    a = "a = " + 引用(a) + "\nprint a" 打印一个

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

    a = "a = @\n打印一个" 打印一个

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

    a = "a = @\n打印一个" 打印 a.replace("@", 引用(a))

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

    a = "a = @\nprint a.replace(\"@\", 引用(a))" 打印 a.replace("@", 引用(a))

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

    嗯,你应该确保你只替换 占位符的第一次出现。 如果你使用第二个占位符, 您可以避免需要引用字符串。

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


    ¹通过让程序读取其源文件

    【讨论】:

    • 但是如何避免在 replace(\"@\",quoted(a)) 部分中用 a 替换 @?据我了解,替换应该只发生在@的第一次出现,即@\nprint。我对吗?也就是说replace应该只替换第一次出现的符号?
    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

      通常的方法(当你不能作弊时*)是编写一些将其源编码为字符串常量的东西,然后将该常量打印出两次:一次作为字符串文字,一次作为代码。这绕过了“每次我写一行代码,我必须再写一个来打印出来!”问题。

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

      【讨论】:

      • 其实你能拥有的最小的C文件是:main; dsm$ echo main\; > test.c dsm$ gcc -o test test.c test.c:1: 警告:数据定义没有类型或存储类 dsm$ ./test Segmentation fault dsm$ dsm$
      • 许多 C 编译器会将一个 0 字节的文件编译成一个不输出任何内容并终止的可执行文件。
      【解决方案4】:

      为了好玩,我在 Scheme 中想出了一个,我为此骄傲了大约 5 分钟,直到我发现之前已经被发现。无论如何,为了更好地计算 Lisp 中数据和代码的对偶性,对游戏的“规则”进行了轻微修改:它不是打印出程序的源代码,而是一个返回自身的 S 表达式:

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

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

      【讨论】:

      • 我一直认为这些都算在内,因为进入 REPL,你实际上确实看到程序又出来了。
      • 不算数,因为在 REPL 中你可以只写一个字符串,例如"a" 在 ruby​​ 中,它会自行返回。
      【解决方案5】:

      一个想法是考虑编码以及如何赋予某些东西双重含义,以便它可以用于以几种形式输出某些东西。还有一点需要注意的是,这类问题是有限制的,因为除了程序输出本身之外没有任何规则,空程序是一种解决方案。

      【讨论】:

        【解决方案6】:

        实际阅读和打印您的源代码怎么样?一点都不难!!这是php中的一个:

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

        【讨论】:

          【解决方案7】:

          在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."
          

          【讨论】:

            【解决方案8】:

            我为对此感兴趣的人做了一个 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()
            

            【讨论】:

              【解决方案9】:

              在 bash 中真的很简单

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

              空文件,空输出

              【讨论】:

              • 请分享更多细节。 OP 要求用编译语言提供解决方案,我不会说 bash 脚本是以任何方式编译的
              【解决方案10】:

              在红宝石中:

              puts File.read(_ _ FILE _ _)

              【讨论】:

              • 实际上,几乎所有语言都有编译器(选项)可以将源代码引入二进制文件。但是阅读您的编译器/解释器免费提供给您的信息根本不是这个问题的重点。
              • 奎因在接受输入或从文件中读取时无效
              猜你喜欢
              • 2015-04-27
              • 2014-11-29
              • 2015-03-05
              • 2010-11-21
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2016-05-08
              相关资源
              最近更新 更多