使用虚函数调用时节省堆栈空间

时间:2014-06-08 22:45:37

标签: c++ embedded microcontroller

我目前正在使用C ++开发STM32μ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个字节,因为它们:

  1. 获取堆栈上的参数
  2. 为其函数调用分配堆栈
  3. 将输入复制到新分配的堆栈部分的正确位置
  4. 执行函数调用
  5. 将输出复制回堆栈上的正确位置以获取传入参数
  6. 现在,我们最近才转而使用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注意这种传递风格的行为并强制它尽可能多地节省堆栈空间吗? 我真的很茫然,因为我只使用POD开始......

1 个答案:

答案 0 :(得分:2)

虽然您无法说服gcc自动更改堆栈的布局,但您当然可以通过定义一个struct来手动设置参数,并将共享指针传递给{{1 }}

以下是如何做到这一点:

struct

现在您可以分配struct TxRxParams { uint8_t *tx; size_t lentx; const uint8_t *rx; const size_t lenrx; }; 一次,并将指针传递给各种函数,无论是否为虚拟,以节省堆栈空间。