为什么参数从右到左进栈

原因是由于可变长参数。

如今GCC已经支持按声明顺序进栈,这里分析传统的函数调用入栈。

前提

了解函数调用,所涉及栈帧分配,见下图1:


图1:函数调用栈帧

这个图2也有意思,把函数调用之间的关系展示了出来。


图2:函数调用关系

理论分析

假设现在有函数f,固定参数m个,可变参数n(未知)个,假设所有参数都是32位整数,如果不是整数,也可以根据参数类型,推出参数地址,为了简单画图,在此使用整数。

自右向左(逆变量声明顺序)

那么调用栈图3:


图3:自右向左入栈的调用栈

虽然不知道可变参数n的大小,但是,依然可以根据固定参数的大小m,找到可变参数的开始位置,然后去访问就可以了。至于访问第n+1个可变参数,会造成什么问题,我们一会讨论。

自左向右(按变量声明顺序)

那么调用栈图4:


图4:自左向右入栈的调用栈

在只知道ebp的情况下,而不知道可变参数n的大小,不能确定可变参数和参数的分解,怎么确定参数1,参数m的地址呢?不确定他们怎么能访问呢?真相就是这样子,你无法确定各参数的地址

如何实现自左向右入栈

使用另外的寄存器指向参数1。那么就可以访问固定参数,已经可变参数的区域也就确定了。

自右向左访问参数超过范围

未定义。

以printf为例:

printf("%d %d\n", 1);

这条语句输出另个整数,但可变参数只给了一个整数1,那么访问第二个整数的时候必然也就“越界”了。
假设1的地址为ptr,那么会把(char *)ptr+sizeof(int),这个地址上的数据解析为一个整数输出。如果这个区域是它不能访问的,还会造成非法访问,如果可以访问,数据也是错误的。

要列出所有可能的出顺序,我们可以使用回溯法。在C++中,我们可以通过递归来实现这个过程。下面是一个示例代码: ```cpp #include <iostream> #include <vector> #include <string> void generateSequences(std::string& input, std::string& stack, std::string& output, std::vector<std::string>& result) { if (input.empty() && stack.empty()) { result.push_back(output); return; } // 如果输还有字符,可以进栈 if (!input.empty()) { char ch = input.front(); input.erase(input.begin()); // 移除第一个字符 stack.push_back(ch); // 进栈 generateSequences(input, stack, output, result); input.insert(input.begin(), ch); // 恢复输字符串 stack.pop_back(); // 恢复状态 } // 如果不为空,可以出 if (!stack.empty()) { char ch = stack.back(); stack.pop_back(); // 出 output.push_back(ch); // 添加到输出序列 generateSequences(input, stack, output, result); output.pop_back(); // 恢复输出序列 stack.push_back(ch); // 恢复状态 } } int main() { std::string input = "qwert"; std::string stack; std::string output; std::vector<std::string> result; generateSequences(input, stack, output, result); for (const auto& seq : result) { std::cout << seq << std::endl; } return 0; } ``` 这个程序定义了一个`generateSequences`函数,它通过递归的方式生成所有可能的出顺序。主要思路是: 1. 如果输字符串还有字符,则将该字符进栈。 2. 如果不为空,则将顶字符出并添加到输出序列中。 3. 每次递归调用后,恢复输字符串和的状态,以便尝试其他可能性。 在`main`函数中,我们初始化了输字符串、、输出序列和一个结果向量,然后调用`generateSequences`函数来生成所有可能的出顺序,最后打印结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值