Question

I've got some structs to initialise, which would be tedious to do manually. I'd like to create a macro that will help me with it... but I'm not sure the C preprocessor is good enough for this.

I've got structs which represent menus. They consist of function pointers only:

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;

That allows me to write the functions and separate functions as (.c file):

ON_BUTTON(blah) { ... }

and menus as (.h file):

ON_BUTTON(blah);
ON_DISPLAY(blah);
menu_frame menu_frame_blah = {
   menu_frame_blah_button,
   NULL,
   menu_frame_blah_display,
   NULL
};

Is there any way I can fold the menu definition into one define? I could do something that expands MENU(blah, menu_frame_blah_button, NULL, menu_frame_blah_display, NULL) of course, but is there any way to:

  • make it shorter (NULL or some name)
  • remove the need of ON_BUTTON(...); from before the struct

Ideally, I'd like MENU(blah, button, NULL, display, NULL) to both define the handlers and the menu struct itself. I don't know for example how to prevent expanding the last term into ON_SWITCH(NULL).

Or maybe I should approach it from some other way?

Was it helpful?

Solution

You cannot do conditional macro expansion in C, so that your macro would be expanded differently depending on the arguments, as in: you cannot use #if within macro definition.

I guess the best you could get would be something like MENU(blah, ITEM(blah,button), NULL, ITEM(blah,display), NULL), and you still need a separate set for prototypes because of lack of conditional expansion.

Personally, I would write a simple script to generate that sort of boilerplate C code. One that would understand your desired syntax. In Python or whatever suits you best…

OTHER TIPS

I've written Python scripts to generate this sort of code for me before. You may want to go that route and just work the script into your build process.

You can program conditionals, finite loops, default arguments and all such stuff in the preprocessor alone. The Boost library has an implementation of some of that in their preprocessor section. Boost is primarily for C++, but the preprocessor stuff should basically work in C as well.

By such techniques you can write complicated macros but that are simple to use. It gets a bit simpler to implement when using C99 instead of C89 (you have named initializers and VA_ARGS), but still.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top