这个程序如何复制自己?

PDP*_*PDP 13 c quine

此代码来自Hacker's Delight.它说这是C中最短的程序,长度为64个字符,但我不明白:

    main(a){printf(a,34,a="main(a){printf(a,34,a=%c%s%c,34);}",34);}
Run Code Online (Sandbox Code Playgroud)

我试着编译它.它编译3个警告,没有错误.

hac*_*cks 7

该计划依赖于这些假设

  • 返回类型mainint
  • 函数的参数类型int默认为
  • 该参数a="main(a){printf(a,34,a=%c%s%c,34);}"将首先进行评估.

它将调用未定义的行为.C中不保证函数参数的评估顺序.
虽然,这个程序的工作原理如下:

赋值表达式 a="main(a){printf(a,34,a=%c%s%c,34);}"将分配串"main(a){printf(a,34,a=%c%s%c,34);}"a并的值赋值表达式将是"main(a){printf(a,34,a=%c%s%c,34);}"太按C标准--C11:6.5.16

赋值运算符将值存储在左操作数指定的对象中.赋值表达式赋值后具有左操作数的值 [...]

考虑到上述赋值运算符的语义,程序将被扩展为

 main(a){
      printf("main(a){printf(a,34,a=%c%s%c,34);}",34,a="main(a){printf(a,34,a=%c%s%c,34);}",34);
}  
Run Code Online (Sandbox Code Playgroud)

ASCII 34".说明符及其相应的参数:

%c ---> 34 
%s ---> "main(a){printf(a,34,a=%c%s%c,34);}" 
%c ---> 34  
Run Code Online (Sandbox Code Playgroud)

一个更好的版本

main(a){a="main(a){a=%c%s%c;printf(a,34,a,34);}";printf(a,34,a,34);}  
Run Code Online (Sandbox Code Playgroud)

它的4性格更长,但至少遵循K&R C.


zne*_*eak 5

它依赖于C语言的几个怪癖和(我认为)未定义的行为.

首先,它定义了main函数.声明一个没有返回类型或参数类型的函数是合法的,并且它们将被假定为int.这就是该main(a){部分有效的原因.

然后,它调用printf4个参数.由于它没有原型,因此假定它返回int并接受int参数(除非你的编译器隐含地声明它,就像Clang那样).

第一个参数是假定的int,并且argc位于程序的开头.第二个参数是34(双引号字符的ASCII).第三个参数是赋值表达式,它将格式字符串分配给a并返回它.它依赖于指向int的转换,这在C中是合法的.最后一个参数是数字形式的另一个引号字符.

在运行时,%c格式说明符用引号%s替换,用格式字符串替换,然后再次获得原始源.

据我所知,论证评估的顺序是不确定的.这个quine是有效的,因为赋值a="main(a){printf(a,34,a=%c%s%c,34);}"a被作为第一个参数传递之前被评估printf,但据我所知,没有规则可以强制执行它.此外,这不能在64位平台上工作,因为指针到int的转换会将指针截断为32位值.事实上,即使我可以看到它在某些平台上是如何工作的,但它在我的计算机上无法使用我的编译器.