源代码与其输出完全相同的程序
Program which source code is exactly the same as its output
我越想弄明白这个令人困惑的谜,就越想放弃。
char *s = "char *s = %c%s%c; main(){printf(s,34,s,34);}"; main(){printf(s,34,s,34);}
这种一行源代码怎么会在程序执行时生成完全相同的输出,这种程序有什么共同的概念吗?
从 printf 的第一个参数中获取该字符串:
'char *s = %c%s%c; main(){printf(s,34,s,34);}'
并在
处进行替换
%c = 34 = '"' //(same for both %c)
%s = 'char *s = %c%s%c; main(){printf(s,34,s,34);}'
printf 只会做一次替换(不是递归的),所以结果是:
'char *s = "char *s = %c%s%c; main(){printf(s,34,s,34);}"; main(){printf(s,34,s,34);}'
这叫做Quine。
那么让我们看看 main()
做了什么:
printf(s,34,s,34);
34 是字符 "
(双引号)的 ASCII 码,所以这等同于:
printf(s, '"', s, '"');
printf(3)
的第一个参数是格式字符串。传递的字符串是:
"char *s = %c%s%c; main(){printf(s,34,s,34);}"
因此,printf(3)
将准确输出,但请注意 %c
、%s
和 %c
格式说明符,它们指示 printf(3)
打印一个字符,后面跟着一个字符串,后面跟着那个地方的另一个字符,分别是第2、3、4个参数。
字符,如我们所见,都是"
,字符串又是s
(同一个字符串)。所以程序输出为:
char *s = "X"; main(){printf(s,34,s,34);}
其中X
是程序中的字符串s
。所以我们得到这个作为输出:
char *s = "char *s = %c%s%c; main(){printf(s,34,s,34);}"; main(){printf(s,34,s,34);}
有趣的是,这是程序源本身。
要理解代码,首先简化并重新格式化:
char *s = "some format string";
main() {
printf(s,34,s,34);
}
所以它使用 s
作为格式化字符串来打印三个实体:34
、字符串 s
本身和 34
。在这种情况下,格式化字符串 s
的重要部分是:
char *s = "... %c%s%c ..."
这意味着两个 34
变成双引号 ("
) 并且格式化字符串 s
只是作为普通字符串打印。现在您应该看到格式化字符串 s
的 rest 只是整个程序的副本。
我越想弄明白这个令人困惑的谜,就越想放弃。
char *s = "char *s = %c%s%c; main(){printf(s,34,s,34);}"; main(){printf(s,34,s,34);}
这种一行源代码怎么会在程序执行时生成完全相同的输出,这种程序有什么共同的概念吗?
从 printf 的第一个参数中获取该字符串:
'char *s = %c%s%c; main(){printf(s,34,s,34);}'
并在
处进行替换%c = 34 = '"' //(same for both %c)
%s = 'char *s = %c%s%c; main(){printf(s,34,s,34);}'
printf 只会做一次替换(不是递归的),所以结果是:
'char *s = "char *s = %c%s%c; main(){printf(s,34,s,34);}"; main(){printf(s,34,s,34);}'
这叫做Quine。
那么让我们看看 main()
做了什么:
printf(s,34,s,34);
34 是字符 "
(双引号)的 ASCII 码,所以这等同于:
printf(s, '"', s, '"');
printf(3)
的第一个参数是格式字符串。传递的字符串是:
"char *s = %c%s%c; main(){printf(s,34,s,34);}"
因此,printf(3)
将准确输出,但请注意 %c
、%s
和 %c
格式说明符,它们指示 printf(3)
打印一个字符,后面跟着一个字符串,后面跟着那个地方的另一个字符,分别是第2、3、4个参数。
字符,如我们所见,都是"
,字符串又是s
(同一个字符串)。所以程序输出为:
char *s = "X"; main(){printf(s,34,s,34);}
其中X
是程序中的字符串s
。所以我们得到这个作为输出:
char *s = "char *s = %c%s%c; main(){printf(s,34,s,34);}"; main(){printf(s,34,s,34);}
有趣的是,这是程序源本身。
要理解代码,首先简化并重新格式化:
char *s = "some format string";
main() {
printf(s,34,s,34);
}
所以它使用 s
作为格式化字符串来打印三个实体:34
、字符串 s
本身和 34
。在这种情况下,格式化字符串 s
的重要部分是:
char *s = "... %c%s%c ..."
这意味着两个 34
变成双引号 ("
) 并且格式化字符串 s
只是作为普通字符串打印。现在您应该看到格式化字符串 s
的 rest 只是整个程序的副本。