Как работает программа выводящий собственный код на С?

Есть програмка, которая выводит свой же код:

#include <stdio.h>

int main() {
    const char *code = 
        "#include <stdio.h>\n\n"
        "int main() {\n"
        "    const char *code = \n"
        "        \"%s\";\n"
        "    printf(code, code);\n"
        "    return 0;\n"
        "}\n";
    printf(code, code);
    return 0;
}

Можете подробно объяснить как она работает, почему в printf() дважды передается code? Вот как я пока что понимаю: мы первым аргументом передаем строку т.е code и внутри этой строки есть спецификатор %s и далее через запятую мы передаем ещё раз code чтобы вставить вместо этого спецификатора.


Ответы (1 шт):

Автор решения: Stanislav Volodarskiy

Плохо работает программа. Она выводит что-то отдалённо похожее на свой код, но этого недостаточно.

оригинал печать
#include <stdio.h>
int main() {
const char *code =
"#include <stdio.h>\n\n"
"int main() {\n"
" const char *code = \n"
" "%s";\n"
" printf(code, code);\n"
" return 0;\n"
"}\n";
printf(code, code);
return 0;
}



#include <stdio.h>

int main() {
const char *code =
"#include <stdio.h>

int main() {
const char *code =
"%s";
printf(code, code);
return 0;
}
";
printf(code, code);
return 0;
}

Да, вы разобрались верно: через трюк с печатью форматной строки через саму себя, программа пытается напечатать свой код два раза. Это первый шаг к созданию полноценного квайна.

Попробуйте разобраться как устроена программа ниже. Она печатает каждую свою строку два раза: один раз как код, второй – как строковый литерал из массива code:

#include <stdio.h>

const char *code[] = {
    "#include <stdio.h>",
    "",
    "const char *code[] = {",
    "};",
    "",
    "int main() {",
    "    for (int i = 0; i < 3; ++i) {",
    "        puts(code[i]);",
    "    }",
    "    for (int i = 0; i < 24; ++i) {",
    "        fputs(\"    \\\"\", stdout);",
    "        for (const char *s = code[i]; *s != '\\0'; ++s) {",
    "            switch (*s) {",
    "            case '\"' : fputs(\"\\\\\\\"\", stdout); break;",
    "            case '\\\\': fputs(\"\\\\\\\\\", stdout); break;",
    "            default  : putchar(*s)          ; break;",
    "            }",
    "        }",
    "        puts(\"\\\",\");",
    "    }",
    "    for (int i = 3; i < 24; ++i) {",
    "        puts(code[i]);",
    "    }",
    "}",
};

int main() {
    for (int i = 0; i < 3; ++i) {
        puts(code[i]);
    }
    for (int i = 0; i < 24; ++i) {
        fputs("    \"", stdout);
        for (const char *s = code[i]; *s != '\0'; ++s) {
            switch (*s) {
            case '"' : fputs("\\\"", stdout); break;
            case '\\': fputs("\\\\", stdout); break;
            default  : putchar(*s)          ; break;
            }
        }
        puts("\",");
    }
    for (int i = 3; i < 24; ++i) {
        puts(code[i]);
    }
}
→ Ссылка