这个奎因是如何工作的?

How does this quine work?

我刚遇到这个 quine 问题,但没有人真正研究它是如何工作的:C/C++ program that prints its own source code as its output

char*s="char*s=%c%s%c;main(){printf(s,34,s,34);}";main(){printf(s,34,s,34);}

我特别不明白的是,即使我更改了整数,以下内容也具有相同的输出:

char*s="char*s=%c%s%c;main(){printf(s,34,s,34);}";main(){printf(s,5,s,11);}

它仍然打印 34s!有人可以一步一步地指导我吗?

让我们首先格式化代码以跨越多行。这打破了它是奎因的事实,但更容易看到发生了什么:

char* s = "char*s=%c%s%c;main(){printf(s,34,s,34);}";

main() { 
   printf(s, 34, s, 34);
}

本质上,这是一个字符串 s 的声明,它是一个 printf 格式的字符串,后面跟着一个调用 printf 的函数 main 的声明四个参数。 (这个 main 的定义使用了 C 中老式的 "implicit int" 规则,其中假定函数具有 int 作为 return 类型,除非另有说明。我相信这是目前在 C 中已弃用,并且可以肯定这不是合法的 C++ 代码。)

那么这个 printf 调用到底在做什么?好吧,注意到 34 是双引号的 ASCII 代码可能会有所帮助,所以行

printf(s, 34, s, 34);

本质上是

printf(s, '"', s, '"');

这意味着 "print the string s with arguments ", s, and "." 那么 s 是什么?它显示在这里:

char* s = "char*s=%c%s%c;main(){printf(s,34,s,34);}";

这遵循了一个常见的自我引用技巧。忽略 %c%s%c 部分,这基本上是程序其余部分的字符串表示形式。 %c%s%c 部分出现在它变得自指的地方。

那么如果你调用 printf(s, '"', s, '"') 会发生什么?这会将占位符%c%s%c填入"char*s=%c%s%c;main(){printf(s,34,s,34);}",也就是字符串s的字符串内容。与字符串 s 的其余部分结合,因此 proints

char*s="char*s=%c%s%c;main(){printf(s,34,s,34);}";main(){printf(s,34,s,34);";

这是程序的源代码。我认为这有点简洁 - 我所知道的一般 Quine 程序的最接近英文翻译是 "print this string, the second time in quotes"(尝试一下 - 看看会发生什么!),这基本上就是这样做的。

您问的是为什么将数字更改为 5 和 11 并没有改变正在打印的 34。没错!字符串文字 s 中硬编码了 34,因此在对 printf 的调用中更改 5 和 11 不会改变它。它所做的是不再打印字符串内部的引号 s 而是打印非打印字符。