扫码关注官方订阅号
如何编写一个可以输出自己源代码的程序,要满足以下要求:1.该程序不可以从外部读取输入。2.该程序的输出不可以为空。想了很久始终无法想明白要如何做到。。。
除非源码文件还在,不然二进制文件无法将本身再解释成源代码,解释其他二进制也不行。目前,很多编译器在解析源代码时候都会进行优化,对应到二进制的一条条指令。这些指令没办法再翻译成高级语言了。就像2+2=4,但4不一定2+2.
C语言的话,用宏定义应该可以构造特殊的程序,使其输出恰好等于其源码,但是如果你想要输出全部源代码(包括include和注释)就做不到了。要想从编译好的可执行文件中获得代码就属于逆向工程了,而且有些编译过程本身就是不可逆的。
最简单的C:
EXEC_OUTPUT(a = 1);
不过只支持简单表达式,不支持本身有字符串的表达式,不支持宏,不支持全局变量。。。
((lambda (x)
(list x (list (quote quote) x))) (quote (lambda (x) (list x (list (quote quote) x)))))
#!/bin/cat
编译后的二进制程序显然不行。脚本程序依赖解释器,也不符合要求。所以这是一个鸡生蛋蛋生鸡的问题?
php
简洁版:
echo file_get_content(__FILE__);
酷炫版:
highlight_file(__FILE__);
在编译期将读取源代码,以字符串形式存放到程序中程序运行时根据不同参数输入这么个思路
首先,为了限制篇幅,我在外部定义一个quote函数,作用是将一个字符串中的特殊字符转义起来。这个函数就不纳入源文件了,否则代码太长:
quote
// quote.h char* quote(const char* s) { static char buf[512]; for(unsigned len = 0; *s; s++) { if(*s == '\n') { buf[len++] = '\\'; buf[len++] = 'n'; } else if(*s == '\"') { buf[len++] = '\\'; buf[len++] = '"'; } else buf[len++] = *s; } return buf; }
这个源文件是这样的:
#include <stdio.h> #include <quote.h> int main() { const char *s = "#include <stdio.h>\n#include <quote.h>\n\nint main()\n{\n const char *s = \"%s\";\n printf(s, quote(s));\n}"; printf(s, quote(s)); }
s就是一个把整个源文件压扁成字符串,然后在字符串里代表自身的地方用%s代替。总的来说只是算printf的一种有趣的应用罢了。
s
%s
printf
这个有个缺陷,就是在你改动源码的时候,你要相应地改动s。你可以将quote函数也纳入源码,但是要相应地在加入单引号和斜杠的转移。
又没说不能用编译指令……
x.c:
X
Makefile:
x: x.c gcc 2.c -DX="main(){puts(\"X\");}"
微信扫码关注PHP中文网服务号
QQ扫码加入技术交流群
Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号
PHP学习
技术支持
返回顶部
除非源码文件还在,不然二进制文件无法将本身再解释成源代码,解释其他二进制也不行。目前,很多编译器在解析源代码时候都会进行优化,对应到二进制的一条条指令。这些指令没办法再翻译成高级语言了。就像2+2=4,但4不一定2+2.
C语言的话,用宏定义应该可以构造特殊的程序,使其输出恰好等于其源码,但是如果你想要输出全部源代码(包括include和注释)就做不到了。要想从编译好的可执行文件中获得代码就属于逆向工程了,而且有些编译过程本身就是不可逆的。
最简单的C:
define EXEC_OUTPUT(expr) printf("%s", #expr); expr;
EXEC_OUTPUT(a = 1);
不过只支持简单表达式,不支持本身有字符串的表达式,不支持宏,不支持全局变量。。。
((lambda (x)
#!/bin/cat编译后的二进制程序显然不行。脚本程序依赖解释器,也不符合要求。
所以这是一个鸡生蛋蛋生鸡的问题?
php
简洁版:
酷炫版:
在编译期将读取源代码,以字符串形式存放到程序中
程序运行时根据不同参数输入
这么个思路
首先,为了限制篇幅,我在外部定义一个
quote函数,作用是将一个字符串中的特殊字符转义起来。这个函数就不纳入源文件了,否则代码太长:这个源文件是这样的:
s就是一个把整个源文件压扁成字符串,然后在字符串里代表自身的地方用%s代替。总的来说只是算printf的一种有趣的应用罢了。这个有个缺陷,就是在你改动源码的时候,你要相应地改动
s。你可以将quote函数也纳入源码,但是要相应地在加入单引号和斜杠的转移。又没说不能用编译指令……
x.c:
Makefile: