I have some pre-processor definitions that make storing UI text easy in a single array (see below). Also makes supporting other languages less cumbersome.
#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_)
the result is an array of strings and an enum representing indexes in the array.
However, since it is an array of pointers to constant char*, it takes up ram which is very scarce on this device. The couple of large string tables in the program are taking up ~30% of the available RAM. so this can't be ignored.
Dependency of RAM would go to zero if the enum values were starting positions of the null-terminated sub-strings in one large const char string stored in code space.
i.e:
menu_sztable[] = "One\0Two\0Three\0Press Enter\0";
STR_ONE -> 0
STR_TWO -> 4
STR_Three -> 8
STR_PressEnter -> 14
Is there a clever way to use the C-Preprocessor to make this? I'd like to avoid building up the enum manually or having to to write a pre-build command program that converts the arrays.
static const char* const name##_sztable[] = /* ... */which should put the array of pointers into ROM with most embedded device tool chains (assuming that ROM/flash space isn't an issue as well)?