C/C++;将自己的源代码打印为输出的程序
说它叫奎因,有人给了下面的密码:C/C++;将自己的源代码打印为输出的程序,c,quine,C,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> #include//corrected from#include 这样printf()就可以工作了 从字面上看,由于上述程序没有打印#inclu
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>
#include//corrected from#include
这样printf()
就可以工作了
从字面上看,由于上述程序没有打印#include
,因此它不是解决方案(?)
我对“打印自己的源代码”的字面要求以及这类问题的任何目的感到困惑,特别是在采访中。这里的技巧是大多数编译器将编译而不需要包含
stdio.h
他们通常只会发出警告。奎因在与编程语言和一般执行相关的定点语义中有一定的深度根源。它们在理论计算机科学方面具有一定的重要性,但在实践中却毫无意义 它们是一种挑战或技巧 字面需求就是你所说的,字面:你有一个程序,它的执行产生自己作为输出。这就是为什么它被认为是一个固定点:通过语言语义执行程序本身就是它的输出 如果你把计算表示成一个函数,你就会得到
f(program, environment) = program
对于quine,环境被认为是空的(你没有任何输入,之前也没有预先计算过)关于quine程序的采访问题的主要目的通常是看看你以前是否遇到过它们。它们在任何其他意义上几乎都没有用处 上述代码可以适度升级,以生成符合C99的程序(根据GCC),如下所示: 汇编 代码 如果源代码和输出之间存在差异,则会报告
“奎因样”技术的一个几乎有用的应用 早在我年轻的时候,我就制作了一个双语“自我复制”节目。它是shell脚本和Informix-4GL(I4GL)源代码的组合。使这成为可能的一个属性是I4GL将
{…}
视为注释,但shell将其视为I/O重定向的一个单元。I4GL也有#…EOL
注释,shell也是如此。文件顶部的shell脚本包含数据和操作,用于以不支持指针的语言重新生成复杂的验证操作序列。数据控制了我们生成的I4GL函数以及每个函数的生成方式。然后编译I4GL代码,每周验证从外部数据源导入的数据
如果将文件(称为
file0.4gl
)作为shell脚本运行并捕获输出(称为file1.4gl
),然后将file1.4gl
作为shell脚本运行并在file2.4gl
中捕获输出,那么这两个文件file1.4gl
和file2.4gl
将是相同的。但是,<>代码>文件0.4GL 可能会丢失所有生成的I4GL代码,只要文件顶部的shell脚本“注释”没有被损坏,它就可以重新生成一个自复制文件。 < P>这是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;}
字符串s
主要包含源代码的副本,除了s
本身的内容之外,它在那里有%c%s%c
诀窍在于,在printf
调用中,字符串s
既用作格式,也用作%s
的替换。这导致printf
也将其放入s
的定义中(即在输出文本上)
附加的
10
和34
s对应于换行符和“
字符串分隔符。它们由printf
插入,作为%c
的替代品,因为它们需要在格式字符串中增加一个\
,这将导致格式字符串和替代字符串不同,因此该技巧不再有效。您也可以手动定义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(c++中的基本自释放代码)`//自复制基本代码
[
[
//自复制基本代码
#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
#包括//1行
#包括//2行
使用命名空间std;//3行
//4线
int main(int argc,char*argv[])//第五行
{
char q=34;//第7行
字符串l[]={//8行----代码将在此处暂停,稍后将在第3个for循环中继续
" ",
“#包括//1行”,
“#包括//2行”,
“使用命名空间std;//3行”,
“//4行”,
“int main(int argc,char*argv[])//第五行”,
"{",
“char q=34;//第7行”,
“字符串l[]={//8行”,
“};//第9次继续打印代码的结束部分”//第3次循环从此处开始打印
“对于(int i=0;i<9;i++)//第10个前半段代码”,
“您是否需要#包含printf()的<代码> >不是代码> >代码>代码太老,你不清楚你真的需要它。但是在现代C编译器下升级代码是很好的。在输出结束时没有新行的问题。这个代码当然不是C++代码。好的catch。它是。C++编译器是正确的。不编译上面的代码,只有C编译器才编译。也感谢您对quine实用价值的解释。感谢您更新C99版本。以及“有用的应用程序”"非常感谢!可能值得扩展此答案,以解释如何根据标准推断隐式定义函数的规则。您可能应该提到,数值10和34取决于主机字符编码,对于linefeed和双引号具有dif的平台,需要更改F
#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
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);}
main(a){printf(a="main(a){printf(a=%c%s%c,34,a,34);}",34,a,34);}
#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