Самовоспроизводящаяся программа

Я подвергаю сомнению свое решение последнего упражнения в Accelerated C++:

Напишите самовоспроизводящуюся программу. Такая программа не выполняет ввод и при запуске записывает копию собственного исходного текста в стандартный поток вывода.

Мое решение:

using std::string;
using std::cout;
using std::endl;
using std::ifstream;
using std::getline;

void selfReproduce16_1()
{
    ifstream thisFile("C:\\Users\\Kevin\\Documents\\NetBeansProjects\\Accelerated_C++_Exercises\\Chapter_16.cpp", ifstream::in);

    string curLine;

    bool foundHeader = false;

    while(getline(thisFile, curLine))
    {
        if(!curLine.compare("void selfReproduce16_1()") || foundHeader)
        {
            foundHeader = true;
            cout << curLine << endl;
        }

    }

}

Это только распечатывает исходный текст решения (эта функция). Это то решение, которое они имели в виду?

Я хотел бы динамическое решение, которое не требует жесткого кодирования местоположения исходного файла. Однако я не знаю, как автоматически получить местоположение исходного файла во время выполнения.

Еще одним моментом, связанным с этим, является включение «включенных» файлов и (при обнаружении вызова функции) автоматическое получение местоположения исходного файла, в котором хранится функция. Для меня это было бы настоящим «самовоспроизводящимся». "программа.

Возможно ли это в С++? Если да, то как?


person Kevin    schedule 19.02.2011    source источник
comment
Использование ifstream нарушает правило "Такая программа не использует правило ввода".   -  person James McNellis    schedule 19.02.2011
comment
Очень умное решение. Чтение исходного файла и его вывод. И это делается после прочтения Accelerated C++. Должен сказать, что это слишком ускоренное решение. :D   -  person Nawaz    schedule 19.02.2011
comment
Я думаю, что есть что-то действительно несправедливое в этом современном компьютерном программировании. Я работаю программистом уже 20 лет и не умею писать Quine, а эти... эти новички читают Ускоренное руководство на 350 страниц (проверено на Amazon) и умеют писать Quine... Мне грустно, очень грустный. Так грустно, что я стану поваром или кем-то в этом роде и украду работу у кого-то другого! :-)   -  person xanatos    schedule 19.02.2011
comment
@James: Ах ... Я не принимал никаких входных данных, чтобы не принимать аргументов.   -  person Kevin    schedule 19.02.2011


Ответы (5)


Программа, которая печатает сама себя, называется Quine.

Я думаю, что ваше решение не будет считаться действительным: квинам обычно не разрешается читать файлы (и получать какие-либо другие входные данные). Можно написать программу Quine C++, здесь можно найти множество реализаций quine в нескольких языки.

person peoro    schedule 19.02.2011

Я хотел бы больше динамического решения (которое не требует жесткого кодирования местоположения исходного файла)

Вы знаете, аргументы в основной функции (т.е. argc и argv). Итак, первый argv — это имя исполняемого файла программы. Так что все, что вам нужно, это удалить .exe и заменить на .cpp. Или вы можете извлечь папку из имени файла и найти все исходные файлы и вывести их. Я позволю тебе разобраться. Вот как напечатать имя исполняемого файла:

#include <iostream>

int main(int argc, char** argv) {
  std::cout << argv[0] << std::endl;
  return 0;
};

Проверьте его в своей системе, чтобы увидеть, что он дает. Если он не отображает полный путь, не беспокойтесь, все операции открытия файлов будут выполняться из одного и того же начального относительного каталога, поэтому получение относительного каталога исполняемого файла также даст относительный каталог источнику (при условии, что они находятся в ту же папку).

person Mikael Persson    schedule 19.02.2011
comment
Спасибо! Это как раз ответ на сценарии, которые всплывали в моей голове. - person Kevin; 19.02.2011

Вот простой квайн, который я написал на C++. Он не использует никаких входных данных. Я думаю, что книга искала что-то в этом роде, поскольку они явно исключали ввод (кроме этого, ваше решение для чтения исходного файла является хорошим, и я тоже сначала подумал об этом).

https://gist.github.com/3363087

person Dmitri Shuralyov    schedule 15.08.2012

Я только что закончил этот урок. Нетрудно написать программу, которая не открывает текстовый файл. Все, что вам нужно сделать, это использовать вектор строк, нажимая каждую строку кода, кроме нажатий на вектор, который вы затем используете для циклов один за другим, на самом деле вы можете посмотреть мой код, и, возможно, это будет лучшее объяснение . Единственное, что вы можете не понять, это цикл for, который я использовал для (auto b:a) b — это итератор для a, а auto — это просто быстрый способ его объявить. Вот исходный код.

    #include "stdafx.h"
#include <vector>
#include <string>
#include <iostream>
using namespace std;
int main()
{
vector<string> a;
push:
a.push_back("#include \"stdafx.h\"");
a.push_back("#include <vector>");
a.push_back("#include <string>");
a.push_back("#include <iostream>");
a.push_back("using namespace std;");
a.push_back("using namespace std;");
a.push_back("int main()");
a.push_back("{");
a.push_back("vector<string> a;");
a.push_back("push:");
a.push_back("for(auto b:a)");
a.push_back("{");
a.push_back("cout << b << endl;");
a.push_back("if(b == \"push:\")");
a.push_back("{");
a.push_back("for(auto c:a)");
a.push_back("{");
a.push_back("cout << \"a.push_back(\\\"\" << c << \\\"\";\" << endl;");
a.push_back("}");
a.push_back("}");
a.push_back("}");
a.push_back("return 0;");
a.push_back("}");
for(auto b:a)
{
    cout << b << endl;
    if(b == "push:")
    {
        for(auto c:a)
        {
            cout << "a.push_back(\"" << c << "\");" << endl;
        }
    }
}
return 0;
}
person Marvin Schafer    schedule 23.09.2013

Если встроенная сборка разрешена, поместите ее где-нибудь в исходный файл. Он опирается на ассемблер GNU, что позволяет встраивать любые данные извне.

#include <cstdint>
extern "C"
{
#if __gnu_linux__

#define BLOB(identifier,filename) \
asm(".pushsection .data\n" \
    "\t.local " #identifier "_begin\n" \
    "\t.type " #identifier "_begin, @object\n" \
    "\t.align 16\n" \
    #identifier "_begin:\n" \
    "\t.incbin \"" filename "\"\n\n" \
\
    "\t.local " #identifier "_end\n" \
    "\t.type " #identifier "_end, @object\n" \
    "\t.align 1\n" \
    #identifier "_end:\n" \
    "\t.byte 0\n" \
    "\t.popsection\n"); \
\
extern const uint8_t identifier##_begin[];\
extern const uint8_t identifier##_end[]

#elif _WIN32

#define BLOB(identifier,filename) \
asm(".data\n" \
    "\t.align 16\n" \
    #identifier "_begin:\n" \
    "\t.incbin \"" filename "\"\n\n" \
\
    "\t.align 1\n" \
    #identifier "_end:\n" \
    "\t.byte 0\n" \
    "\t.text\n"); \
\
extern const uint8_t identifier##_begin[];\
extern const uint8_t identifier##_end[]

#else
    #error "Cannot include binary files"
#endif
}

BLOB(source,__FILE__);

Теперь у вас есть два идентификатора source_begin и source_end. Прокрутите массив и распечатайте данные через ваш любимый интерфейс.

int main()
    {
    auto ptr=source_begin;
    auto ptr_end=source_end;
    while(ptr!=ptr_end)
        {
        putchar(*ptr);
        ++ptr;
        }
    return 0;
    }

Демонстрация: http://coliru.stacked-crooked.com/a/d283f6dd9118b164

person user877329    schedule 11.11.2016