Инитация структуры через чрезмерное использование макроса
-
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)
для определения обработчиков и самой структуры меню. Например, я не знаю, как предотвратить расширение последнего термина в ON_BUTTON(...);
.
или, может быть, я должен подойти к этому из-за другого пути?
Решение
Вы не можете выполнить условное расширение макроса в C, так что ваш макрос будет расширен по-разному в зависимости от аргументов, как в: вы не можете использовать #if в рамках определения макроса.
Я думаю, что лучшее, что вы можете получить, будет что-то вроде MENU(blah, ITEM(blah,button), NULL, ITEM(blah,display), NULL)
, и вам все еще нужен отдельный набор для прототипов из-за отсутствия условного расширения.
Лично я бы написал простой скрипт для создания такого рода кода CoverPlate C.Тот, который бы понял ваш желаемый синтаксис.В Python или что угодно вас лучше всего ...
Другие советы
Я написал сценарии Python, чтобы сгенерировать этот код для меня раньше.Вы можете захотеть пойти на этот маршрут и просто работать сценарий в ваш процесс сборки.
Вы можете запрограммировать условные контуры, конечные петли, аргументы по умолчанию и все такие вещи в препроцессоре в одиночку.Библиотека BOOST имеет реализацию некоторых из них в их препроцессоре.Boost в основном для C ++, но препроцессорные вещи должны в основном работать в C, а также.
По таким методам вы можете написать сложные макросы, но это просто в использовании.Это становится немного проще реализовать при использовании C99 вместо C89 (вы назвали инициализаторы и va_args ), но все же.