在这个解决方案中,void(**rptr)()和main()中的调用是如何在C++中打印没有循环的1-100的

How does void(**rptr)() and the call in main() work in this solution to printing 1-100 with no loops in C++?

本文关键字:1-100 循环 C++ 打印 解决方案 void main rptr 调用      更新时间:2024-04-28

在Quora的回答中,我偶然发现了这段代码,并想了解发生了什么:如何在C++中打印1到100而不使用循环、goto或递归?

我问了我的编程老师,他说他对alloca()不太熟悉,但他确信这个程序有未定义的行为,我最好问SO。值得注意的是,Quora上的答案OP并不能保证这会在其他人的系统上起作用。

我很难理解void(**rptr)()的作用以及main()中的调用是如何工作的,为什么是* 200?。

#include <iostream>
#include <stdlib.h>
int num;
void(**rptr)();
void foo() {
if(num >= 100) exit(0);
std::cout << ++num << std::endl;
*rptr++ = foo;
}
int main() {
rptr = (void(**)())alloca(sizeof(*rptr) * 200) - 1;
foo();
return 0;
}

这是一个利用未定义行为的可怕黑客。分析未定义的行为是毫无意义的,但有时深入研究并找出确切原因是很有趣的。

基本上,alloca(...)正在分配足够的内存来在堆栈上存储200个函数指针。到目前为止,很不寻常,但没什么不好的。但关键是结尾处的-1-它的返回内存,即该存储之前的一个。因此rptr将堆栈指向未知位置。

然后调用CCD_ 7。在foo的末尾,我们将foo的地址写入rptr。但是rptr在有效内存之前是一个,所以我们正在重写其他内容。

其他东西恰好是foo返回的返回地址(应该是main(。因此,它基本上没有返回到main,而是"返回"到foo的开头。这种情况一直重复,直到我们到达出口。

它基本上适度控制了堆栈粉碎。并且只适用于具有调用约定的体系结构,其中返回地址被放入该庄园的堆栈中。