我的 AVR 微控制器固件中有一个简单的命令行界面,基于这样的结构:
typedef struct {
const char *name;
const char *usage;
const char *help;
void (*handler)(char **last);
} command_t;
extern command_t *cli_commands[];
我希望能够以尽可能 DRY 的方式在不同的模块中声明命令。到目前为止,我有它,所以我定义我的函数是这样的:
COMMAND_IMPL(replay, "replay <n>", "Replay frame n") {
// 'last' argument is for strtok_t
}
然后我必须在我的一个.c
文件中有这个:
COMMAND_DECL(list);
COMMAND_DECL(clear);
COMMAND_DECL(replay);
COMMAND_TABLE
COMMAND(list)
COMMAND(clear)
COMMAND(replay)
END_COMMAND_TABLE
我的宏看起来像这样:
#define COMMAND_IMPL(name, usage, help) \
static void cli_handle_##name##_command(char **);\
command_t cli_##name##_command = {#name, usage, help, cli_handle_##name##_command};\
static void cli_handle_##name##_command(char **last)
#define COMMAND_DECL(name) extern command_t cli_##name##_command;
#define COMMAND_TABLE command_t *cli_commands[] = {
#define COMMAND(name) ((command_t *) &cli_##name##_command),
#define END_COMMAND_TABLE NULL };
可以做得比这更好吗?该项目已经绑定到 avr-gcc,所以我不介意它是否是一个 GCC-only 解决方案。使用链接器功能的解决方案也可以(我正在编译为 ELF)。我在想也许我可以将命令条目放在不同的部分,并将其链接到已知的某个地方,但我想不出它会如何被终止。