Первая программа представляет собой пример реализации 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), с аргументом substituion (C.99 § 6.10.3.1) и
#
"stringifying" оператора (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()
.
Структура этих программ во многом вдохновлена реализацией программы «quine» на «вымышленном» языке BlooP, представленной в книге Gödel, Escher, Bach: An Eternal Golden Braid Дугласом Р. Хофстадтером (зачисленной за то, что она придумала термин «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");})
Кажется, очень похоже на http://stackoverflow.com/questions/8200668/can-you-help-me-with-a-short-code-that-can-print-себя – devnull
@devnull: Я изменил вопрос, чтобы сделать его более отличительным. Тот, на который вы ссылаетесь, на самом деле не соответствует ни одному стандарту С. – jxh
Aha! поэтому вам кажется, что это соответствует стандарту. Тогда почему вы задаете один и тот же вопрос? – devnull