C中数组索引和数组内容的静态映射
Static mapping of array index and array content in C
我有一个参数列表。每个参数都由一个唯一标识符 (ParamID
) 和一些与该参数关联的其他数据 (&ParamX
、SomeOtherDataX
) 定义。所有可用参数都组织在一个 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[]
)发生变化,则必须更新以指向所需的参数。
问题:
基本上我的代码需要从 ParamID
到 ParameterList[]
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] = { ... } 来额外确保索引匹配。
请注意,上面的代码在很大程度上依赖于格式化,这可能会也可能不会。
而且无论如何,有些人可能会觉得这样的技巧不合适。
我有一个参数列表。每个参数都由一个唯一标识符 (ParamID
) 和一些与该参数关联的其他数据 (&ParamX
、SomeOtherDataX
) 定义。所有可用参数都组织在一个 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[]
)发生变化,则必须更新以指向所需的参数。
问题:
基本上我的代码需要从 ParamID
到 ParameterList[]
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] = { ... } 来额外确保索引匹配。
请注意,上面的代码在很大程度上依赖于格式化,这可能会也可能不会。
而且无论如何,有些人可能会觉得这样的技巧不合适。