调用自身的宏打印自己?

jxh*_*jxh 3 c quine language-lawyer

以下程序看起来像一个调用自身的C宏.

#define q(k)int puts();int main(){puts(#k"\nq("#k")");}
q(#define q(k)int puts();int main(){puts(#k"\nq("#k")");})
Run Code Online (Sandbox Code Playgroud)

它编译并运行良好.它打印出来.

这段代码真的是C吗?也就是说,它是否依赖于标准C之外的任何东西才能正常工作?

@devnull指出这个问题有一个类似的程序:

#define q(k)main(){return!puts(#k"\nq("#k")");}
q(#define q(k)main(){return!puts(#k"\nq("#k")");})
Run Code Online (Sandbox Code Playgroud)

该程序是否依赖标准C之外的任何东西才能正常工作?

jxh*_*jxh 8

第一个程序是在C中实现quine的一个例子.在高级别,它定义了一个宏q(),它创建了一个main()打印出两行的定义.第一行是参数本身,第二行是包含在对q()自身的调用中的参数.那么,以下程序:

#define q(k)int puts();int main(){puts(#k"\nq("#k")");}
q(foo)
Run Code Online (Sandbox Code Playgroud)

扩展到:

int puts();int main(){puts("foo""\nq(""foo"")");}
Run Code Online (Sandbox Code Playgroud)

编译并运行时,会产生输出:

foo
q(foo)
Run Code Online (Sandbox Code Playgroud)

用宏定义本身代替fooquine中的结果.宏并不真正调用自身,它是在定义它的同一文本上调用的.在C中,宏不是递归扩展的(C.99§6.10.3.42).

如问题中所述,该程序使用严格的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.314).
  • 字符串文字串联(C.99§5.1.1.21).
  • 默认main()返回值(C.99§5.1.2.2.31).

特别值得注意的是,该程序不依赖于字符的ASCII编码.

该程序将在C.89-90编译器上编译,但main()不为C.89-90定义不返回值的行为.通过return 0;在调用之后添加,可以对程序进行简单修改以符合C.89-90标准puts().

至于第二个项目,它也是一个quine.但是,它不是C.89-90,也不是C.99,也不符合C.11.这是因为它依赖于puts()返回逻辑非运算符的正数,以便返回值0.但是,C只需要puts()在成功时返回非负值(C.99§7.19.7.103).只有C.89-90允许隐式函数声明(C.89,§3.3.2.2).通过删除return!,然后return 0;puts()通话后添加,可以修改程序以符合C.89-90 .

这些课程的结构在很大程度上受到了"虚构"语言BlooP的quine项目的启发,该项目由道格拉斯·R·霍夫施塔特(Douglas R. Hofstadter)撰写的哥德尔,埃舍尔,巴赫:永恒的金色辫子一书中提出(由于创造了这个术语而得到了认可)奎因).

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'].
Run Code Online (Sandbox Code Playgroud)

顺便说一下,这是一个程序的版本,它以相反的顺序打印出它的源代码:

#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");})
Run Code Online (Sandbox Code Playgroud)