【问题标题】:Static mapping of array index and array content in CC中数组索引和数组内容的静态映射
【发布时间】:2015-04-20 16:14:03
【问题描述】:

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

// 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[] 表中定义的参数子集的引用。该列表也应该驻留在 ROM 中。我基本上想访问参数子集的所有关联数据。

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

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

问题:

基本上我的代码需要从ParamIDParameterList[] 表的索引的映射,最好使用预处理器并且仅在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
};

我的内存不足,所以我更喜欢只使用 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也不是一种选择。

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

【问题讨论】:

  • 这行得通吗?自从我从事嵌入式系统工作以来已经有一段时间了,但我发现编译器可以正确地将&something_else_I_just_compiled_into_ROM 放入 ROM 中,这让我感到惊讶。
  • 我认为如果我的 const 定义中的某些内容在编译时间上不是真正恒定的,我会得到一个编译错误。因此,我认为这会进入 ROM。这个想法对吗?
  • @Simon,C 没有 ROM 的概念。此外,const-qualified 变量不能 进入 ROM,除非你正在编写固件,因为任何必须加载到内存中的东西都不能加载到 ROM 中。如果您正在编写固件,那么您需要查阅工具链的文档以确定如何安排在固件映像(即在 ROM 中)分配变量存储,但它是不一定与const 合格有关。
  • 是的,实际上我正在为 DSP 编写固件,它使用闪存作为非易失性存储器。我将更深入地研究工具链,但我依靠当前配置将const 变量放入闪存中。

标签: c arrays struct macros c-preprocessor


【解决方案1】:

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

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 $1_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] = { ... } 来确保索引匹配。

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

【讨论】:

  • 对我来说,使用脚本似乎是解决这个问题的一种非常有效的方法。不过也没多想。无论如何,我可以更改我计算机上的工具链,但其他编写代码的人可能不会。所以不幸的是,这在我的情况下不起作用。感谢您的宝贵意见!
【解决方案2】:

我是这样做的吗,我需要灵活性

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

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

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

【讨论】:

  • 您的意思是为我的 ParameterList 的一行声明一个枚举,例如:typedef enum = {ParamID, ParamAddr, Data}
猜你喜欢
  • 1970-01-01
  • 2020-01-31
  • 1970-01-01
  • 2021-12-28
  • 2016-09-23
  • 2015-03-27
  • 2017-01-22
  • 1970-01-01
相关资源
最近更新 更多