C/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>

таким образом printf() может работать

Буквально, так как вышеприведенная программа не печатала #include <stdio.h>, это не решение (?)

Меня смущает буквальное требование "печатать свой собственный исходный код" и любые цели такого рода проблем, особенно на собеседованиях.

11 ответов

Решение

Хитрость в том, что большинство компиляторов будут компилироваться без необходимости включать 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 <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 -

Если есть разница между исходным кодом и выводом, об этом будет сообщено.


Практически полезное применение "квино-подобных" техник

Еще во времена моей юности я подготовил двуязычную программу "самовоспроизводства". Это была комбинация сценария оболочки и исходного кода Informix-4GL (I4GL). Одним из свойств, которые сделали это возможным, было то, что I4GL лечит { ... } как комментарий, но оболочка воспринимает это как единицу перенаправления ввода / вывода. I4GL также имеет #...EOL комментарии, как и оболочка. Сценарий оболочки в верхней части файла содержит данные и операции для создания сложной последовательности операций проверки на языке, который не поддерживает указатели. Данные контролировали, какие функции I4GL мы сгенерировали и как каждый из них был сгенерирован. Затем был скомпилирован код I4GL для проверки данных, импортируемых из внешнего источника данных на еженедельной основе.

Если вы запустили файл (назовите его file0.4gl) в качестве сценария оболочки и захватил вывод (вызов этого file1.4gl), а затем побежал file1.4gl в качестве сценария оболочки и захватил вывод в file2.4gl, два файла file1.4gl а также file2.4gl будет идентичным Тем не мение, file0.4gl может отсутствовать весь сгенерированный код I4GL и до тех пор, пока сценарий оболочки 'comment' в верхней части файла не будет поврежден, он будет самовоспроизводиться.

Quine имеет некоторые глубинные корни в семантике с фиксированной запятой, связанной с языками программирования и выполнениями в целом. Они имеют некоторое значение, связанное с теоретической информатикой, но на практике у них нет цели.

Это своего рода вызов или уловка.

Буквальное требование - это как раз то, что вы сказали, буквально: у вас есть программа, ее выполнение выдает себя в качестве вывода. Не больше и не меньше, поэтому это считается фиксированной точкой: выполнение программы через семантику языка само по себе является выходом.

Так что, если вы выразите вычисление как функцию, вы получите

f(program, environment) = program

В случае quine среда считается пустой (у вас нет ничего в качестве входных данных, ни предварительно вычисленных ранее)

Вы также можете определить прототип 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++`// Самовоспроизводящийся базовый код

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

// Самовоспроизводящийся базовый код

#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

Вот версия, которая будет принята компиляторами 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 (в выходном тексте, то есть)

дополнительный 10 а также 34s соответствуют переводу строки и " разделитель строк. Они вставлены printf в качестве замены %cс, потому что они потребуют дополнительного \ в строке формата, что приведет к различию строки форматирования и замены, поэтому хитрость больше не будет работать.

      /*  C/C++ code that shows its own source code without and with File line number and C/C++ code that shows its own file path name of the file. With Line numbers */

#include<stdio.h>

#include<string.h>

#include<iostream>

using namespace std;



#define SHOW_SOURCE_CODE 

#define SHOW_SOURCE_FILE_PATH

/// Above two lines are user defined Macros

int main(void) {



/* shows source code without File line number. 

#ifdef SHOW_SOURCE_CODE

        // We can append this code to any C program

    // such that it prints its source code.



    char c;

    FILE *fp = fopen(__FILE__, "r");



    do

    {

        c = fgetc(fp);

        putchar(c);

    }

    while (c != EOF);



    fclose(fp);

          // We can append this code to any C program

    // such that it prints its source code.



#endif

*/

#ifdef SHOW_SOURCE_FILE_PATH



       /// Prints location of C this C code.

   printf("%s \n",__FILE__);



#endif


#ifdef SHOW_SOURCE_CODE
        /// We can append this code to any C program
    /// such that it prints its source code with line number.

unsigned long ln = 0;
 FILE *fp = fopen(__FILE__, "r");
int prev = '\n';
int c;  // Use int here, not char
while((c=getc(fp))!=EOF) {
  if (prev == '\n'){
    printf("%05lu ", ++ln);
  }
  putchar(c);
  prev = c;
}
if (prev != '\n') {
  putchar('\n');  /// print a \n for input that lacks a final \n
}
printf("lines num: %lu\n", ln);

    fclose(fp);
          /// We can append this code to any C program
    /// such that it prints its source code with line number.

#endif

    return 0;
}

Моя версия без использования %c:

      #include <stdio.h>
#define S(x) #x
#define P(x) printf(S(S(%s)),x)
int main(){char y[5][300]={
S(#include <stdio.h>),
S(#define S(x) #x),
S(#define P(x) printf(S(S(%s)),x)),
S(int main(){char y[5][300]={),
S(};puts(y[0]);puts(y[1]);puts(y[2]);puts(y[3]);P(y[0]);putchar(',');puts(S());P(y[1]);putchar(',');puts(S());P(y[2]);putchar(',');puts(S());P(y[3]);putchar(',');puts(S());P(y[4]);puts(S());fputs(y[4],stdout);})
};puts(y[0]);puts(y[1]);puts(y[2]);puts(y[3]);P(y[0]);putchar(',');puts(S());P(y[1]);putchar(',');puts(S());P(y[2]);putchar(',');puts(S());P(y[3]);putchar(',');puts(S());P(y[4]);puts(S());fputs(y[4],stdout);}

Не уверен, что вы хотели получить ответ о том, как это сделать. Но это работает:

      #include <cstdio>
int main () {char n[] = R"(#include <cstdio>
int main () {char n[] = R"(%s%c"; printf(n, n, 41); })"; printf(n, n, 41); }

Если вы игрок в гольф, это более миниатюрная версия:

      #include<cstdio>
int main(){char n[]=R"(#include<cstdio>
int main(){char n[]=R"(%s%c";printf(n,n,41);})";printf(n,n,41);}
main(a){printf(a="main(a){printf(a=%c%s%c,34,a,34);}",34,a,34);}
#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;
}                              
Другие вопросы по тегам