调用自身的宏打印自己?

时间:2013-08-01 00:00:08

标签: c language-lawyer quine

以下程序看起来像一个调用自身的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以外的任何内容才能正常工作?

1 个答案:

答案 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),带有变量替换(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编译器上编译,但是没有为{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");})
相关问题