C-Preprocessor并在低内存中实现字符串表

时间:2012-10-09 17:19:03

标签: c string storage c-preprocessor

我有一些预处理器定义,可以在单个数组中轻松存储UI文本(见下文)。也使得支持其他语言不那么麻烦。

#define DECLARE_STRING_ENUM_FST(name, value) name
#define DECLARE_STRING_ENUM_SND(name, value) value
#define DECLARE_STRING_ENUM(name, macro) \
    typedef enum name { macro(DECLARE_STRING_ENUM_FST) } name; \
    static const char* name##_sztable[] = { macro(DECLARE_STRING_ENUM_SND) }; \

// this is a string table usage 
#define MSG_ENUM_(X) \
    X(STR_ONE, "One"), \
    X(STR_TWO, "Two"), \
    X(STR_THREE, "Three"), \
    X(STR_PRESS_ENTER, "Press Enter")

// the actual declaration is here
DECLARE_STRING_ENUM(menu, MSG_ENUM_)

结果是一个字符串数组和一个表示数组中索引的枚举。

然而,因为它是一个指向常量char *的指针数组,所以它占用ram,这在这个设备上是非常稀缺的。程序中的几个大字符串表占用了大约30%的可用RAM。所以这不容忽视。

如果枚举值是存储在代码空间中的一个大的const char字符串中的以null结尾的子字符串的起始位置,则RAM的依赖性将变为零。

即:

menu_sztable[] = "One\0Two\0Three\0Press Enter\0";
STR_ONE -> 0
STR_TWO -> 4
STR_Three -> 8
STR_PressEnter -> 14

有没有一种聪明的方法来使用C-Preprocessor来实现这一目标?我想避免手动构建枚举或者必须编写转换数组的预构建命令程序。

4 个答案:

答案 0 :(得分:1)

这不是一个完整的解决方案,也许是中途......

#include <stdlib.h>
#include <stddef.h>
static struct foo {
    char arr0[5];
    char arr1[4];
    char arr2[4];
} tmp = { "Zero","One","Two"};
enum {
   ARR0 = offsetof(struct foo, arr0),
   ARR1 = offsetof(struct foo, arr1),
   ARR2 = offsetof(struct foo, arr2)
};

int main()
{
      printf("%d %d %d\n",ARR0,ARR1,ARR2);
      return 0;
}

无法记住链接器选项,但在拆解时,我会得到:

    .file   "tst.c"
    .data     // manually replace with .text
_tmp:
    .ascii "Zero\0"
    .ascii "One\0"
    .ascii "Two\0"  // manually insert .data here, recompile and run...
    .def    ___main;        .scl    2;      .type   32;     .endef

答案 1 :(得分:1)

如果您制作指针数组const大多数(全部?)工具链会将该数组放入ROM / flash中,这通常对空间有较小的问题:

static const char* const name##_sztable[] = /* ... */
//                 ^^^^^

答案 2 :(得分:0)

你可以先定义一大堆编译时常量来保存你的字符串的位置,比如

#define DEFINE_LENGTH(NAME, STR) NAME ## _POS,       \
      NAME ## _DUMMY = (NAME ## _POS + sizeof(STR))

在枚举声明中

enum {
  ... your macro expansion goes here ...
};

然后通过连接

创建一个长字符串
#define DEFINE_COMPONENT(NAME, STR) STR "\0"

在长字符串

的初始化内部
char const table[] = ... your macro expansion goes here ...;

现在你的字符串指针是用

获得的
#define DEFINE_VARIABLE(NAME, STR) *const NAME = &table[NAME ## _POS]

在以下设置中:

char const  ... your macro expansion goes here ...;

(也许这里和那里仍然存在一些语法错误,但我希望你能得到它。)

如果您使用宏元数据包(例如boost或P99),那么所有这些都会更简单。

答案 3 :(得分:0)

为什么不这样做:

#if ENGLISH
#define STR_ONE "one"
#define STR_TWO "two"
...
#elif SPANISH
#define STR_ONE "uno"
#define STR_TWO "dos"
...
#endif

您是否有理由需要偏移而不是字符串指针?