手把手教你用C语言写一个简单的quine(输出自身的程序)
第一步,写个简单的框架
#include<stdio.h>
int main(){
printf("#include<stdio.h>\nint main(){\n\tprintf();\n\treturn 0;\n}");
return 0;
}
printf的东西先留空。
这时你会发现printf里面的东西需要是这句东西本身,如果把这句话复制进去,你会发现最内层还存在一个空的括号,反反复复下去就无底洞了。所以需要换个思路:
用变量。
第二步,考虑把printf的东西扔到变量里,然后使用格式符输出。
#include<stdio.h>
int main(){
char *s="#include<stdio.h>\nint main(){\n\tprintf(s);\n\treturn 0;\n}";
printf(s);
return 0;
}
有人要问了,你这不还没在字符串s里面定义如何写char嘛,如果在字符串里面把s写出来,那不又成刚才那样的无底洞了?
且慢,由于s此时是printf的第一个参数,我们完全可以利用好printf的功能——%s嘛。有了这招,我们就不用那样写无底洞了,用%s参数把s放进去就行了。
#include<stdio.h>
int main(){
char *s="#include<stdio.h>\nint main(){\n\tchar *s=%s;\n\tprintf(s,s);\n\treturn 0;\n}";
printf(s,s);
return 0;
}
这里有个小技巧,printf(s,s),第一个s格式描述符把程序框架输出,%s的位置交给第二个s把字符串s本身再输出一遍。
且慢...输出的结果貌似不太对?
答案是由于转义字符的缘故。其中我们以明文形式写的\n、\t等转义字符,在输出的时候会变成换行,制表符。我们希望它输出程序框架的时候是正常输出制表和换行的,而在输出s内容的时候直接保留原文...
第三步,继续利用printf的参数
如果用%c,然后用字符的ASCII码代替转义字符,就没这问题了。
逐一把转义字符写成ASCII码,堆在printf的后面,写完后把字符串s内容中的printf参数也这样换一遍,就大功告成了。
printf的参数会变得很多,不过能正常运行就行。
#include<stdio.h>
int main(){
char *s="#include<stdio.h>%cint main(){%c%cchar *s=%c%s%c;%c%cprintf(s,10,10,9,s,10,9,10,9,10);%c%creturn 0;%c}";
printf(s,10,10,9,34,s,34,10,9,10,9,10);
return 0;
}
成功运行,撒花!