以下程序看起来像一个调用自身的C宏。
#define q(k)int puts();int main(){puts(#k"\nq("#k")");}
q(#define q(k)int puts();int main(){puts(#k"\nq("#k")");})
It compiles and runs fine。它打印出来。
这段代码真的是C吗?也就是说,它是否依赖标准C之外的任何东西才能正常工作?
@devnull指出this question有一个类似的程序:
#define q(k)main(){return!puts(#k"\nq("#k")");}
q(#define q(k)main(){return!puts(#k"\nq("#k")");})
此程序是否依赖标准C以外的任何内容才能正常工作?
答案 0 :(得分:8)
第一个程序是在C中实现quine的一个例子。在高级别,它定义了一个宏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)。
如问题中所述,该计划使用严格的C.99设置(-pedantic -std=c99
)在GCC下进行无投诉编制。该程序仅使用标准C功能,并符合C.99和C.11。
#
“字符串化”运算符(C.99§6.10.3.2)。main()
返回值(C.99§5.1.2.2.3¶1)。特别值得注意的是,该程序不依赖于字符的ASCII编码。
程序将在C.89-90编译器上编译,但是没有为{89}定义不从main()
返回值的行为。通过在调用return 0;
后添加puts()
,可以对该程序进行简单修改,使其符合C.89-90标准。
至于第二个项目,它也是一个quine。但是,它不是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)。通过删除return!
,然后在return 0;
调用后添加puts()
,可以修改程序以符合C.89-90。
这些课程的结构在很大程度上受到了道格拉斯·霍夫斯塔特(Douglas R. Hofstadter)在书籍Gödel, Escher, Bach: An Eternal Golden Braid中提出的“虚构”语言BlooP中的quine项目的实施的启发(因为创造了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");})