C中数组索引和数组内容的静态映射

Static mapping of array index and array content in C

我有一个参数列表。每个参数都由一个唯一标识符 (ParamID) 和一些与该参数关联的其他数据 (&ParamXSomeOtherDataX) 定义。所有可用参数都组织在一个 table 中,它在 C 中作为结构数组 (ParameterList[]) 实现。因此,在每一行我都可以看到一个参数的所有关联数据。以下代码片段应该(希望)使这一点更清楚:

// predefined IDs; not changeable!
#define PARAM_ID_A   10
#define PARAM_ID_B   12
#define PARAM_ID_C   14

// the basic structure of my parameter list
typedef struct ParameterList_t {
  int    ParamID,
  *int   ParamAddr,
  *float SomeConnectedData
}

// definition of my list in ROM
const ParameterList_t ParameterList[] = {
  { PARAM_ID_A, &Param1, SomeOtherData1},
  { PARAM_ID_B, &Param2, SomeOtherData2},
  { PARAM_ID_C, &Param3, SomeOtherData3}
};

现在我想创建另一个列表,其中包含对 ParameterList[] table 中定义的参数子集的引用。此列表也应驻留在 ROM 中。我基本上想访问参数子集的所有关联数据。

const *ParameterList_t ParameterSubListA[] = {
     &ParameterList[2],   // parameter: PARAM_ID_B
     &ParameterList[3],   // parameter: PARAM_ID_C
};

这里的问题是代码会被很多人维护,参数列表(ParameterList[])可能会经常变化,参数会被排序到table开头或者后面中间。这意味着如果子列表 (ParameterSubListA[]) 的索引(index = row in ParameterList[])发生变化,则必须更新以指向所需的参数。

问题:

基本上我的代码需要从 ParamIDParameterList[] table 的索引的映射,最好使用预处理器,并且只在 ROM 中。我找到了不同的实现方式,但都不令人满意:

选项 1:

启动时在RAM中自动生成一个列表,将ParamID映射到ParameterList[]中的索引。我得到的是一个数组,可以称为 CrossRefTable[]:

IndexOfParameterA_InParameterList = CrossRefTable[PARAM_ID_A];

我的子列表将如下所示(不能再保持不变了 :/ ):

*ParameterList_t ParameterSubListA[] = {
     &ParameterList[CrossRefTable[PARAM_ID_B]],   // parameter: PARAM_ID_B
     &ParameterList[CrossRefTable[PARAM_ID_C]],   // parameter: PARAM_ID_C
};

我的 RAM 不足,所以我更喜欢只使用 ROM 的解决方案。

选项 2:

使用预定义的宏 __COUNTER__,它会随着每次调用而递增,并在每一行中生成一个宏:

const ParameterList_t ParameterList[] = {
  { PARAM_ID_A, &Param1, SomeOtherData1},
  #define PARAM_IDX_A __COUNTER__
  { PARAM_ID_B, &Param2, SomeOtherData2},
  #define PARAM_IDX_B __COUNTER__
  { PARAM_ID_C, &Param3, SomeOtherData3}
  #define PARAM_IDX_C __COUNTER__
};

我的子列表将如下所示:

const *ParameterList_t ParameterSubListA[] = {
     &ParameterList[PARAM_IDX_B],   // parameter: PARAM_ID_B
     &ParameterList[PARAM_IDX_C],   // parameter: PARAM_ID_C
};

我会赞成这个选项,显然不能使用 GCC。

其他选项: 我还认为可能有使用 X-MACROS 的可能性,但我不确定。 Boost 也不是一种选择。

希望我的解释有点清楚...

如果我这样做,我需要灵活性

然后我会定义一个与数据 table 相匹配的枚举。 (不需要枚举的实际实例,只需要定义

然后声明一个数组,其中包含枚举中的一些值。

该数组中的值是数据数组的偏移量

由于数据是静态的,我会说继续并静态初始化它。 如果编译器功能不够,请使用外部工具。

parameter_list.c:

const struct ParameterList_t ParameterList[] = {
    { PARAM_ID_A, &Param1, SomeOtherData1},
    { PARAM_ID_C, &Param2, SomeOtherData2},
    { PARAM_ID_B, &Param3, SomeOtherData3}
};

#include "parameter_list_index.h"

const *ParameterList_t ParameterSubListA[] = {
    &ParameterList[PARAM_ID_C_INDEX],
    &ParameterList[PARAM_ID_B_INDEX],
};

parameter_list.px:

#!/usr/bin/perl -n
print "#define _INDEX ".($n++)."\n" if
    /^const.*ParameterList\[\]/../^}/ and /^\s*{\s*([^,]+)/;

生成文件:

parameter_list.o: parameter_list.c parameter_list.h

parameter_list_index.h: parameter_list.c
    ./parameter_list.px $< > $@

这只是一个大概的想法,您的实现当然可能会有所不同。 您可以选择以相同的方式生成 ParameterList[] 或使用 [PARAM_ID_A_INDEX] = { ... } 来额外确保索引匹配。

请注意,上面的代码在很大程度上依赖于格式化,这可能会也可能不会。
而且无论如何,有些人可能会觉得这样的技巧不合适。