1

我有一些预处理器定义,可以轻松地将 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 的依赖性将变为零。

IE:

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

有没有一种聪明的方法来使用 C 预处理器来做这个?我想避免手动构建枚举或必须编写一个转换数组的预构建命令程序。

4

4 回答 4

2

如果您将指针const数组设为大多数(全部?)工具链,则会将该数组放入 ROM/flash 中,这通常不会出现空间问题:

static const char* const name##_sztable[] = /* ... */
//                 ^^^^^
于 2012-10-09T19:49:47.073 回答
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
于 2012-10-09T17:51:44.320 回答
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 之类的宏元包,这一切都会变得更简单。

于 2012-10-09T18:07:48.373 回答
0

为什么不这样做:

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

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

于 2012-10-09T18:18:39.720 回答