C / C ++程序打印自己的源代码作为输出

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

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

但是,显然你必须添加

 #include  //corrected from #include  

这样printf()可以工作。

从字面上看,由于上面的程序没有打印#include ,它不是解决方案(?)

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

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

他们通常会发出警告。

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

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

汇编

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

 #include  char*s="#include %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 ,以及线条几乎足够短,无需水平滚动条即可在SO上工作。稍加努力,无疑可以做得足够短。

测试

quine程序的酸测试是:

 ./quine | diff quine.c - 

如果源代码和输出之间存在差异,则会报告。


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

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

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

您也可以手动定义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);} 

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

他们是一种挑战或诡计。

文字要求就是你说的,文字:你有一个程序,它的执行产生自己作为输出。 没有更多或更少,这就是为什么它被认为是一个固定的点:通过语言语义执行程序本身就是它的输出。

因此,如果您将计算表达为函数,那么您将拥有该函数

 f(program, environment) = program 

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

这是一个将被C ++编译器接受的版本:

 #include const char*s="#include%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的定义中(在输出文本上,即)

额外的1034对应于换行符和"字符串分隔符。它们由printf插入作为%c s的替换,因为它们需要格式字符串中的附加\ ,这将导致格式和替换 -字符串不同,所以这个技巧将不再起作用。

Quine(c ++中的基本自复制代码`//自我复制基本代码

[ http://www.nyx.net/~gthompso/quine.htm#links%5D [ https://pastebin.com/2UkGbRPF#links%5D

//自我复制基本代码

 #include  //1 line #include  //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  //1 line ", "#include  //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 
 main(a){printf(a="main(a){printf(a=%c%s%c,34,a,34);}",34,a,34);} 
 #include int main(void) { char a[20],ch; FILE *fp; // __FILE__ Macro will store File Name to the array a[20] sprintf(a,__FILE__); // Opening the file in Read mode fp=fopen(a,"r"); // Taking character by character from file, // you can also use fgets() to take line by line while((ch=fgetc(fp))!=EOF) printf("%c",ch); return 0; }