使用虚函数调用时节省堆栈空间
conserve stack space when using virtual function calls
我目前正在为STM32µC开发c++。基本上,我想为I²c添加一个抽象层,以便拥有虚拟的I²c总线,它实际上位于物理I²c总线上的多路复用器后面。
我们已经有了一个将驱动程序和多路复用逻辑结合起来的驱动程序,在OOP部门明显缺乏…因此,我在I²C访问和虚拟总线实现中添加了间接级别,以将驱动程序与多路复用器逻辑解耦并隐藏全局知识:
Device -> Virtual I²C -> I²C Multiplexer -> Abstracted I²C -> Low-Level I²C
现在我的问题基本上是,每个接口都必须定义一个传输函数
virtual
transmit(const uint8_t address,
uint8_t *tx,
size_t lentx,
const uint8_t *rx,
const size_t lenrx,
const size_t timeout
);
只传递一些参数。通常:
virtual
transmit(...) {
this->driver->transmit(this->address, ...);
}
然而,事实证明,每个虚函数调用会给我的堆栈需求增加40字节,因为它们:
- 获取栈上的参数
- 为函数调用分配堆栈
- 将输入复制到堆栈新分配部分的正确位置 执行函数调用
- 将输出复制回堆栈中传入参数的正确位置
现在,我们只是最近才改用c++,所以我对使用c++进行嵌入式系统开发的微调还不是很了解。然而,对我来说很奇怪的是,已经有三个间接层了,基本上已经耗尽了堆栈空间……例如,我以这种方式单独遍历虚拟调用会损失164字节:设备到虚拟总线,虚拟总线到I²C多路复用器,I²C多路复用器到抽象I²C,真正的调用发生在那里。
理想的解决方案是显而易见的。显然,虚函数调用应该只为它需要传递的额外变量分配尽可能多的空间,并重新排序参数:
Incoming: tx*, len, rx*, len, to
Allocate: tx*, len, rx*, len, to, ___
Reorder : ___, tx*, len, rx*, len, to
Add args: sla, tx*, len, rx*, len, to
---------- Call ----------
Reorder : tx*, len, rx*, len, to, ___
Dealloc : tx*, len, rx*, len, to
Output : tx*, len, rx*, len, to
所以真正的问题是:我能强迫GCC注意到这种传递风格的行为,并强迫它尽可能多地保留堆栈空间吗?
虽然您不能说服gcc自动更改堆栈的布局,但您当然可以通过定义单个struct
来手动更改堆栈布局,并在其上设置参数,并传递指向该struct
的共享指针。
你可以这样做:
struct TxRxParams {
uint8_t *tx;
size_t lentx;
const uint8_t *rx;
const size_t lenrx;
};
现在您可以分配一次TxRxParams
,并将指向它的指针传递给各种函数,无论虚拟还是非虚拟,以节省堆栈空间
相关文章:
- 算法问题:查找从堆栈中弹出的所有序列
- 使用模板进行堆栈实现; "name followed by :: must be a class or namespace"
- Visual Studio(或任何其他工具)能否将地址解释为调用堆栈(boost上下文)的开头
- 为什么调用堆栈数组会导致内存泄漏
- gdb错误:Backtrace已停止:上一帧与此帧相同(堆栈已损坏?)
- 在 leetcode 上提交解决方案时出现堆栈缓冲区溢出错误
- 我的 int main() 中出现堆栈溢出错误
- 堆栈和队列是否像C++中的数组一样传递?
- 拥有映射的现代方法,该映射可以指向或引用已在堆栈上分配的不同类型的数据
- 为什么 STL 容器适配器堆栈中的 top 返回常量引用?
- 从堆栈分配的原始指针构造智能指针
- 在函数范围内在堆栈上分配的数组在离开函数时是否总是被释放?
- 堆栈中大小变量输入错误 (C++)
- 堆栈问题(平衡表达式问题集)
- C++ 在堆栈中包含多态属性的类对象存储
- 用于解析 win64 堆栈跟踪的命令行客户端(可以访问符号服务器)
- 在 C++ 中使用链表进行堆栈
- 变量周围的堆栈'...'已损坏
- 在 gtest 中初始化堆栈上的引用变量的隔离错误
- 使用虚函数调用时节省堆栈空间