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

时间:2012-04-20 00:23:26

标签: c quine

Wikipedia说它被称为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>,所以它不是解决方案(?)

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

8 个答案:

答案 0 :(得分:12)

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

他们通常会发出警告。

答案 1 :(得分:12)

关于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脚本运行并捕获输出(调用file1.4gl),然后将file1.4gl作为shell脚本运行并捕获file2.4gl中的输出,两个文件file1.4glfile2.4gl将是相同的。但是,file0.4gl可能会丢失所有生成的I4GL代码,只要文件顶部的shell脚本“注释”没有损坏,它就会重新生成一个自我复制的文件。

答案 2 :(得分:5)

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

答案 3 :(得分:4)

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

他们是一种挑战或诡计。

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

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

f(program, environment) = program

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

答案 4 :(得分: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的定义中(在输出文本上,即)

其他1034对应于换行符和"字符串分隔符。它们由printf作为%c的替换插入,因为它们在格式字符串中需要额外的\,这会导致格式和替换字符串不同,所以这个伎俩不再适用了。

答案 5 :(得分:0)

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

[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

答案 6 :(得分:-2)

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

答案 7 :(得分:-6)

#include<stdio.h>

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;
}