我正在为 ARM Cortex-M4 处理器编写可重用的 C++ 模块。该模块使用大量存储来完成其任务,并且时间紧迫。
为了允许我的模块的用户自定义其行为,我使用不同的后端类来实现不同的低级任务。其中一个后端是存储后端,这是一种将实际数据存储在不同类型的 volatile /非 volatile RAM 中的方法。它主要由执行速度非常快的 set/get 函数组成,它们将被非常 频繁调用。它们大多是这种形式:
uint8_t StorageBackend::getValueFromTable(int row, int column, int parameterID)
{
return table[row][column].parameters[parameterID];
}
uint8_t StorageBackend::getNumParameters() { return kNumParameters; }
底层表和数组的大小和数据类型取决于用户定义的功能,因此我无法避免使用存储后端。一个主要问题是需要将实际数据放入 RAM 地址空间的特定部分(例如,为了使用外部 RAM),我不想将我的模块限制为特定的存储选项。
现在我想知道选择什么设计模式来将存储方面与我的主模块分开。
- 具有虚函数 的类将是一个简单而强大的选择。但是,我担心在时间紧迫的环境中频繁调用虚拟 set/get 函数的成本。特别是对于存储后端,这可能是一个严重的问题。
- 为模块主类提供用于其不同后端的模板参数(甚至可能使用 CRTP 模式?)。这将避免虚拟功能,甚至允许内联存储后端的设置/获取功能。但是,它需要在头文件中实现整个主类,这不是特别整洁...
- 使用简单的C 风格函数 构成存储后端。
- 对简单的 set/get 函数使用宏(编译后这应该与选项 2 大致相同,所有 set/get 函数都是内联的。)
- 自己定义存储数据结构,并允许使用宏作为数据类型进行自定义。例如。
RAM_UINT8 table[ROWSIZE][COLSIZE]
用户添加#define RAM_UINT8 __attribute__ ((section ("EXTRAM"))) uint8_t
缺点是它需要所有数据位于 RAM 的同一连续部分 - 这在嵌入式目标上并不总是可能的。
不知是否还有更多选择?现在,我倾向于选项 4,因为它足够整洁,但对实际运行时性能的影响为零。
总结一下:在 Cortex-M4 上实现低/零开销存储抽象层的最佳方法是什么?
最佳答案
虚拟成员通常归结为一次额外的查找(如果有的话)。虚函数的 vtable(一种常见的实现方法)通常可以很容易地从“this”指针访问,使用不大于通常在那里的指令将已知的固定地址加载到静态链接函数。
鉴于你已经在做
row*column + offset + size*parameter
(假设您没有重载任何运算符)并且您调用的函数正在传递 3 个参数(所有这些参数都需要加载),如果有的话,这是一个非常小的开销。
但是,这并不是说如果您进行大量访问,调用函数的开销不会让您感到疲倦。不过,答案是允许您一次检索多个值。
关于嵌入式目标上的 C++ : Low overhead storage backend,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35573719/