让我们首先将代码格式化为跨越多行。这打破了它是 quine 的事实,但更容易看到正在发生的事情:
char* s = "char*s=%c%s%c;main(){printf(s,34,s,34);}";
main() {
printf(s, 34, s, 34);
}
本质上,这是一个字符串的声明,s它是一个printf格式化字符串,然后是一个main调用printf四个参数的函数的声明。(这个定义在 C 中main使用老式的“隐式int”规则,除非另有说明,否则假定函数具有int作为返回类型。我相信这目前在 C 中已被弃用,并且肯定知道这不是合法的 C++ 代码。)
printf那么这个电话到底在做什么呢?好吧,注意 34 是双引号的 ASCII 代码可能会有所帮助,所以该行
printf(s, 34, s, 34);
本质上是
printf(s, '"', s, '"');
这意味着“打印s带有参数",s和的字符串"。” 那是什么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,这因此表明
char*s="char*s=%c%s%c;main(){printf(s,34,s,34);}";main(){printf(s,34,s,34);";
这是程序的源代码。我认为这有点简洁——我所知道的与一般 Quine 程序最接近的英文翻译是“打印这个字符串,第二次用引号括起来”(试试看——看看会发生什么!),这基本上就是这样做的。
您在问为什么将数字更改为 5 和 11 并没有改变正在打印的 34。这是正确的!字符串文字s有 34 个硬编码,因此更改调用中的 5 和 11printf不会改变它。它将不再在字符串内部打印引号s,而是打印非打印字符。