在这个解决方案中,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++?
在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
的开头。这种情况一直重复,直到我们到达出口。
它基本上适度控制了堆栈粉碎。并且只适用于具有调用约定的体系结构,其中返回地址被放入该庄园的堆栈中。
相关文章:
- 如何循环打印顶点结构
- 如何在C++中从两个单独的for循环中添加两个数组
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 正在尝试了解输入验证循环
- std::map<struct,struct>::find 找不到匹配项,但是如果我循环通过 begin() 到 end(),我在那里看到匹配项
- 循环后如何继续阅读
- Ardunio UNO解决了多个重叠的定时器循环
- Eigen如何在容器循环中干净地附加矩阵
- 在某些循环内使用vector.push_back时出现分段错误
- 我正在使用嵌套的while循环来解析具有多行的文本文件,但由于某种原因,它只通过第一行,我不知道为什么
- 为什么我的for循环不能正确获取argv
- 如何声明特征矩阵,然后通过嵌套循环初始化它
- 将一副牌循环100次(一副牌)
- 如何在没有同步的情况下使用多个线程(2、4,8、16 个线程)在循环(10,100、1000 个周期)中打印字符串?
- 如何将100位整数放在循环中,并在每个周期上添加 1
- C++ 长度为 100 的循环队列类
- 想知道我的代码有什么问题?一旦播放器名称达到 100,应该输出获胜者,但在之后再次循环
- 使用for循环和rand生成100个随机数,并打印出最小和最大的数字
- 在循环中创建100个不同名称的对象
- 制作骰子游戏.试图让循环在玩家达到100的时候被打破