这个程序有什么作用?
main(_){write(read(0,&_,1)&&main());}
在分析之前,我们先美化一下:
main(_) {
write ( read(0, &_, 1) && main() );
}
首先,您应该知道这_
是一个有效的变量名,尽管它很丑陋。让我们改变它:
main(argc) {
write( read(0, &argc, 1) && main() );
}
接下来,意识到函数的返回类型和参数的类型在 C 中是可选的(但在 C++ 中不是):
int main(int argc) {
write( read(0, &argc, 1) && main() );
}
接下来,了解返回值是如何工作的。对于某些 CPU 类型,返回值始终存储在相同的寄存器中(例如 x86 上的 EAX)。因此,如果您省略一条return
语句,则返回值很可能是最近返回的函数。
int main(int argc) {
int result = write( read(0, &argc, 1) && main() );
return result;
}
对的调用read
或多或少很明显:它从标准 in(文件描述符 0)读取到位于 的内存中&argc
,以获取1
字节。1
如果读取成功则返回,否则返回 0。
&&
是逻辑“与”运算符。当且仅当它的左侧为“真”(从技术上讲,任何非零值)时,它才会评估其右侧。&&
表达式的结果int
是始终为 1(表示“真”)或 0(表示假)的 an。
在这种情况下,右侧调用main
不带参数。在用 1 个参数声明它之后不带参数调用main
是未定义的行为。尽管如此,只要您不关心argc
参数的初始值,它通常会起作用。
然后将结果&&
传递给write()
. 所以,我们的代码现在看起来像:
int main(int argc) {
int read_result = read(0, &argc, 1) && main();
int result = write(read_result);
return result;
}
唔。快速浏览一下手册页会发现它write
需要三个参数,而不是一个。未定义行为的另一种情况。就像main
用太少的参数调用一样,我们无法预测write
它的第二个和第三个参数会收到什么。在典型的计算机上,他们会得到一些东西,但我们不能确定是什么。(在非典型计算机上,可能会发生奇怪的事情。)作者依赖于write
接收之前存储在内存堆栈中的任何内容。而且,他依靠的是第二和第三个论点来阅读。
int main(int argc) {
int read_result = read(0, &argc, 1) && main();
int result = write(read_result, &argc, 1);
return result;
}
修复对 的无效调用main
,添加标题,并扩展&&
我们拥有的:
#include <unistd.h>
int main(int argc, int argv) {
int result;
result = read(0, &argc, 1);
if(result) result = main(argc, argv);
result = write(result, &argc, 1);
return result;
}
结论
该程序在许多计算机上无法按预期工作。即使您使用与原作者相同的计算机,它也可能无法在不同的操作系统上运行。即使您使用相同的计算机和相同的操作系统,它也无法在许多编译器上运行。即使您使用相同的计算机编译器和操作系统,如果您更改编译器的命令行标志,它也可能无法正常工作。
正如我在评论中所说,这个问题没有有效的答案。如果您发现比赛组织者或比赛评委另有说法,请不要邀请他们参加您的下一场比赛。