Первая программа является примером реализации quine на языке C. На высоком уровне она определяет макрос q()
, который создает определение main()
, выводящее две строки. Первая строка — это аргумент сам по себе, вторая строка — это аргумент, завернутый в вызов самого q()
. Итак, следующая программа:
#define q(k)int puts();int main(){puts(#k"\nq("#k")");}
q(foo)
Расширяется в:
int puts();int main(){puts("foo""\nq(""foo"")");}
При компиляции и запуске это приводит к выводу:
foo
q(foo)
Подстановка самого определения макроса вместо foo
приводит к quine. Макрос на самом деле не вызывает сам себя, он вызывается для того же текста, который его определяет. В C макросы не раскрываются рекурсивно (C.99 6.10.3.4 2).
Как отмечено в вопросе, программа без проблем компилируется в GCC с использованием строгих настроек C.99 (-pedantic -std=c99
). Программа использует только стандартные функции языка C и соответствует стандартам C.99 и C.11.
- Замена макроса (C.99 6.10.3) с заменой аргумента (C.99 6.10.3.1) и оператором «строки»
#
(C.99 6.10.3.2).
- Объявление функции с неопределенным списком аргументов (C.99 6.7.5.3 14).
- Конкатенация строковых литералов (C.99 5.1.1.2 1).
- Возвращаемое значение по умолчанию
main()
(C.99 5.1.2.2.3 1).
Особо следует отметить, что программа не использует кодировку символов ASCII.
Программа будет компилироваться на компиляторе C.89-90, но поведение, при котором значение из main()
не возвращается, не определено для C.89-90. Программу можно легко изменить, чтобы она стала совместимой с C.89-90, добавив return 0;
после вызова puts()
.
Что касается второй программы, то это тоже квайн. Однако он не соответствует ни C.89-90, ни C.99, ни C.11. Это связано с тем, что он полагается на puts()
, чтобы вернуть положительное число для оператора логического НЕ, так что возвращаемое значение равно 0
. Однако C требует только, чтобы puts()
возвращал неотрицательное значение в случае успеха (C.99 7.19.7.10 3). Только C.89-90 разрешает неявные объявления функций (C.89, 3.3.2.2). Программу можно изменить, чтобы она соответствовала C.89-90, удалив return!
, а затем добавив return 0;
после вызова puts()
.
Структура этих программ во многом вдохновлена реализацией квайн-программы на «вымышленном» языке BlooP, представленной в книге Гёдель, Эшер, Бах: вечная золотая коса Дугласа Р. Хофштадтера (приписано тому, что он ввел термин quine).
DEFINE PROCEDURE "ENIUQ" [TEMPLATE]: PRINT [TEMPLATE, LEFT-BRACKET,
QUOTE-MARK, TEMPLATE, QUOTE-MARK, RIGHT-BRACKET, PERIOD].
ENIUQ
['DEFINE PROCEDURE "ENIUQ" [TEMPLATE]: PRINT [TEMPLATE, LEFT-BRACKET,
QUOTE-MARK, TEMPLATE, QUOTE-MARK, RIGHT-BRACKET, PERIOD].
ENIUQ'].
Кроме того, вот версия программы, которая выводит исходный код в обратном порядке:
#define q(k)r(char*s){if(*s)r(s+1);putchar(*s);}main(){r(#k"\nq("#k")\n");}
q(#define q(k)r(char*s){if(*s)r(s+1);putchar(*s);}main(){r(#k"\nq("#k")\n");})
person
jxh
schedule
01.08.2013