c - 用宏类型查找替换 "getter"函数

标签 c linux gcc macros c-preprocessor

问题

我正在尝试将用于多种基于硬件的产品的大型平台抽象库 (PAL) 移植到资源有限(即千字节数)的小型嵌入式系统。

当前的 PAL 有一个简单的 getRegister()返回特定产品的注册地址的函数。例如,假设产品名为 coconutpineapple ,代码看起来像这样:

#include "headers/Include/coconut.h"
#include "headers/Include/pineapple.h"

enum prodType {
    PROD_COCONUT = 0,
    PROD_PINEAPPLE,
    PROD_MAX,
    PROD_INVALID = (-1)
};

uint64_t getRegister(enum prodType prod, int regName) {
    uint64_t r = 0;

    switch (prodType) {
        case PROD_COCONUT:
            switch (regName) {
                case REG_BASE:
                    r = COCONUT_REG_BASE;
                    break;
                case REG_CORE:
                    r= COCONUT_REG_CORE;
                    break;
            }
            break;
        case PROD_PINEAPPLE:
            switch (regName) {
                case REG_BASE:
                    r = PINEAPPLE_REG_BASE;
                    break;
                case REG_CORE:
                    r= PINEAPPLE_REG_CORE;
                    break;
            }
            break;
        default:
            // Error.
            break;
    }

    return r;
}

目标

我想将此函数更改为一个简单的编译时宏等价物,以便 getRegister(PROD_COCONUT, REG_BASE) , 只会查看值表并返回适当的寄存器值。这样做的原因是,如果我知道一个平台将只支持 coconut ,我可以使用宏来不包含其他产品的 header (即 pineapple ),并减少程序大小。


到目前为止的工作

到目前为止,我正在考虑这样的事情:

enum regs {
    REG_BASE = 0,
    REG_CORE,
    REG_MAX,
    REG_INVALID = (-1)
};

struct keyValPair {
    int idx;
    enum reg;
    uint64_t val;
};

struct keyValPair tableCoconut[] = {
    { 0, REG_BASE, COCONUT_REG_BASE },
    { 1, REG_CORE, COCONUT_REG_CORE },
};

所以,我希望能够对表进行索引,以便 tableCoconut[REG_BASE]返回 COCONUT_REG_BASE , 返回 O(1) 中的值无需遍历/搜索表。理想情况下,它是编译时宏扩展而不是真正的函数调用。


问题

是否有一种(简单/干净的)方法来实现一些中间映射,以便:

  • 我可以删除 idx来 self 的变量 keyValPair结构(可选)。
  • 有一个O(1) (即非基于搜索的查找)映射(必需)?

这是假设寄存器值不连续且唯一? I'm considering using pieces from a slightly similar question of mine from years ago ,但不能完全得到这种与宏一起使用的双射稀疏到连续映射。我试图通过宏和 ## 创建一个自动递增的索引值创建中间索引的操作,前缀附加到 REG_BASE/REG_CORE通过 ##与预处理器的连接操作。

编辑

并非所有产品都具有相同的寄存器。可能有一个 banana不为 BANANA_REG_CORE 提供条目的下线产品.

最佳答案

鉴于您的枚举从 0 开始并从那里按顺序上升,您可以使用枚举值直接索引到数组中并检索所需的值。虽然这可能不会在编译时发生,但数组查找的复杂度为 O(1),因此应该很快。

所以你可以像这样构建一个数组:

uint64_t tableCoconut[] = {
    COCONUT_REG_BASE,
    COCONUT_REG_CORE
};

tableCoconut[REG_BASE]tableCoconut[REG_CORE] 将在 O(1) 中为您提供所需的值。

您可以进一步扩展它以考虑多种产品:

uint64_t tableAll[2][2] = {
    { COCONUT_REG_BASE, COCONUT_REG_CORE },
    { PINEAPPLE_REG_BASE, PINEAPPLE_REG_CORE },
};

并执行 O(1) 查找,例如 tableAll[PROD_COCONUT][REG_BASE]tableAll[PROD_PINAPPLE][REG_BASE]

关于c - 用宏类型查找替换 "getter"函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47422833/

相关文章:

c - Printf 让程序卡住没有响应

c - C中键盘输入的链表

c - 处理高争用、高频情况的锁

linux - 在 Linux 上以编程方式查看 Microsoft Office 文件

c - 为什么优化会破坏这个 C 代码?

从引导加载程序调用 C 代码

c - 如何修改最大堆中值的优先级?

c++ - 使用 malloc 分配比现有内存更多的内存

linux - C linux 中的 Makefile 错误

c - 函数返回结构编译通过 gcc 失败,但通过 vc6.0 成功