通过宏过度使用进行结构初始化
-
16-09-2020 - |
题
我有一些结构需要初始化,手动完成这会很乏味。我想创建一个宏来帮助我......但我不确定 C 预处理器对此已经足够好了。
我有代表菜单的结构。它们仅包含函数指针:
typedef uint8_t (*button_handler) (uint8_t);
typedef void (*pedal_handler) (void);
typedef void (*display_handler) (void);
typedef void (*menu_switch_handler) (void);
#define ON_BUTTON(x) uint8_t menu_frame_##x##_button (uint8_t button)
#define ON_PEDAL(x) void menu_frame_##x##_pedal (void)
#define ON_DISPLAY(x) void menu_frame_##x##_display (void)
#define ON_SWITCH(x) void menu_frame_##x##_switch (void)
typedef struct menu_frame {
button_handler on_button;
pedal_handler on_pedal;
display_handler on_display;
menu_switch_handler on_switch;
} menu_frame;
这允许我将函数和单独的函数编写为(.c 文件):
ON_BUTTON(blah) { ... }
和菜单(.h 文件):
ON_BUTTON(blah);
ON_DISPLAY(blah);
menu_frame menu_frame_blah = {
menu_frame_blah_button,
NULL,
menu_frame_blah_display,
NULL
};
有什么方法可以将菜单定义折叠成一个定义吗?我可以做一些可以扩展的事情 MENU(blah, menu_frame_blah_button, NULL, menu_frame_blah_display, NULL)
当然可以,但是有什么办法可以:
- 使其更短(NULL 或某个名称)
- 消除需要
ON_BUTTON(...);
从结构之前开始
理想情况下,我想要 MENU(blah, button, NULL, display, NULL)
定义处理程序和菜单结构本身。例如,我不知道如何防止将最后一项扩展到 ON_SWITCH(NULL)
.
或者也许我应该从其他方式来处理它?
解决方案
您无法在 C 中进行条件宏扩展,因此您的宏将根据参数进行不同的扩展,如下所示:不能在宏定义中使用#if。
我想你能得到的最好的就是这样 MENU(blah, ITEM(blah,button), NULL, ITEM(blah,display), NULL)
, ,并且由于缺乏条件扩展,您仍然需要单独的原型集。
就我个人而言,我会编写一个简单的脚本来生成此类样板 C 代码。一个能够理解您想要的语法的人。使用 Python 或任何最适合你的语言......
其他提示
我之前已经编写过 Python 脚本来生成此类代码。您可能想走这条路,并将脚本应用到您的构建过程中。
您可以单独在预处理器中对条件、有限循环、默认参数和所有此类内容进行编程。Boost 库在其预处理器部分中有一些实现。Boost 主要适用于 C++,但预处理器的内容基本上也应该适用于 C。
通过这些技术,您可以编写复杂但易于使用的宏。使用 C99 而不是 C89 时,实现起来会更简单(您已命名初始化程序和 VA_ARGS),但仍然。