14

维基百科说它被称为quine,有人给出了以下代码:

char*s="char*s=%c%s%c;main(){printf(s,34,s,34);}";main(){printf(s,34,s,34);}

但是,显然你必须添加

#include <stdio.h> //corrected from #include <stdlib.h>

这样就printf()可以工作了。

从字面上看,由于上面的程序没有打印#include <stdio.h>,它不是一个解决方案(?)

我对“打印自己的源代码”的字面要求以及此类问题的任何目的感到困惑,尤其是在面试时。

4

7 回答 7

17

关于quine项目的面试问题的主要目的通常是看看你以前是否遇到过它们。它们几乎在任何其他意义上都没有用。

上面的代码可以适度升级,制作一个符合 C99 的程序(根据 GCC),如下:

汇编

/usr/bin/gcc -O3 -g -std=c99 -Wall -Wextra -Wmissing-prototypes \
  -Wstrict-prototypes -Wold-style-definition quine.c -o quine

代码

#include <stdio.h>
char*s="#include <stdio.h>%cchar*s=%c%s%c;%cint main(void){printf(s,10,34,s,34,10,10);}%c";
int main(void){printf(s,10,34,s,34,10,10);}

请注意,这假定了一个代码集,其中"代码点 34 和换行符是代码点 10。与原始版本不同,此版本在末尾打印出换行符。它还包含#include <stdio.h>所需的内容,并且行几乎足够短,可以在没有水平滚动条的情况下处理 SO。再努力一点,它无疑可以做得足够短。

测试

quine 程序的酸性测试是:

./quine | diff quine.c -

如果源代码和输出之间有差异,将会报告。


“类似quine”技术的一个几乎有用的应用

早在我年轻的时候,我就制作了一个双语“自我复制”程序。它是 shell 脚本和 Informix-4GL (I4GL) 源代码的组合。使这成为可能的一个属性是 I4GL 将{ ... }其视为注释,但 shell 将其视为 I/O 重定向单元。I4GL 也有#...EOL注释,shell 也有。文件顶部的 shell 脚本包含数据和操作,以不支持指针的语言重新生成复杂的验证操作序列。数据控制了我们生成了哪些 I4GL 函数以及每个函数是如何生成的。然后编译 I4GL 代码,以每周验证从外部数据源导入的数据。

如果您将文件(调用它file0.4gl)作为 shell 脚本运行并捕获输出(调用 that file1.4gl),然后file1.4gl作为 shell 脚本运行并捕获输出,file2.4gl那么这两个文件将是相同的。但是,可能会丢失所有生成的 I4GL 代码,只要文件顶部的 shell 脚本“注释”没有损坏,它就会重新生成一个自我复制的文件。file1.4glfile2.4glfile0.4gl

于 2012-04-20T04:00:03.313 回答
15

这里的诀窍是大多数编译器都会编译而不需要你包含stdio.h.

他们通常只会发出警告。

于 2012-04-20T00:27:18.063 回答
6

您也可以手动定义 printf 的原型。

const char *a="const char *a=%c%s%c;int printf(const char*,...);int main(){printf(a,34,a,34);}";int printf(const char*,...);int main(){printf(a,34,a,34);}
于 2015-01-15T14:14:21.357 回答
5

quine 在与编程语言和一般执行相关的定点语义中有一些深度根源。它们对理论计算机科学具有一定的重要性,但在实践中它们没有目的。

它们是一种挑战或技巧。

字面要求就是你所说的,字面意思:你有一个程序,它的执行产生自己作为输出。不多也不少,这就是为什么它被认为是一个固定点:通过语言语义执行程序将其自身作为输出。

因此,如果您将计算表达为一个函数,您将拥有

f(program, environment) = program

在 quine 的情况下,环境被认为是空的(您没有任何输入,之前也没有预先计算)

于 2012-04-20T00:30:14.350 回答
1

以下是 C++ 编译器将接受的版本:

#include<stdio.h>
const char*s="#include<stdio.h>%cconst char*s=%c%s%c;int main(int,char**){printf(s,10,34,s,34);return 0;}";int main(int,char**){printf(s,10,34,s,34);return 0;}

测试运行:

$ /usr/bin/g++ -o quine quine.cpp
$ ./quine | diff quine.cpp - && echo 'it is a quine' || echo 'it is not a quine'
it is a quine

该字符串s主要包含源的副本,除了其s自身的内容 - 相反它在%c%s%c那里。

诀窍在于,在printf调用中,字符串s既用作格式用作%s. 这导致printf将其也放入s(在输出文本上,即)的定义中

附加的1034s 对应于换行符和"字符串分隔符。它们printf作为 s 的替换被插入%c,因为它们需要\在格式字符串中添加一个额外的内容,这将导致格式字符串和替换字符串不同,因此该技巧不再适用。

于 2015-01-12T12:07:08.913 回答
1

Quine (Basic self-replicating code in c++`// Self-replicating basic code

[ http://www.nyx.net/~gthompso/quine.htm#links][https://pastebin.com/2UkGbRPF#links ] _

//自我复制基本代码

#include <iostream>     //1 line   
#include <string>       //2 line    
using namespace std;        //3 line    
                //4 line    
int main(int argc, char* argv[])    //5th line  
{
        char q = 34;            //7th line  
        string l[] = {      //8th line  ---- code will pause here and will resume later in 3rd for loop
 " ",
 "#include <iostream>       //1 line   ",
 "#include <string>     //2 line    ",
 "using namespace std;      //3 line    ",
 "              //4 line    ",
 "int main(int argc, char* argv[])  //5th line  ",
 "{",
 "        char q = 34;          //7th line  ",
 "        string l[] = {        //8th line  ",
 "        };                //9th resume printing end part of code  ",      //3rd loop starts printing from here
 "        for(int i = 0; i < 9; i++)        //10th first half code ",
 "                cout << l[i] << endl;     //11th line",
 "        for(int i = 0; i < 18; i++)   //12th whole code ",
 "                cout << l[0] + q + l[i] + q + ',' << endl;    13th line",
 "        for(int i = 9; i < 18; i++)   //14th last part of code",
 "                cout << l[i] << endl;     //15th line",
 "        return 0;         //16th line",
 "}             //17th line",
        };                                          //9th resume printing end part of code  
        for(int i = 0; i < 9; i++)      //10th first half code 
                cout << l[i] << endl;       //11th line
        for(int i = 0; i < 18; i++) //12th whole code 
                cout << l[0] + q + l[i] + q + ',' << endl;  13th line
        for(int i = 9; i < 18; i++) //14th last part of code
                cout << l[i] << endl;       //15th line
        return 0;           //16th line
}               //17th line
于 2017-07-05T09:19:10.967 回答
-2
main(a){printf(a="main(a){printf(a=%c%s%c,34,a,34);}",34,a,34);}
于 2017-06-14T06:49:51.000 回答