views:

55

answers:

3

Hi, 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 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?

A: 

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…

Piotr Kalinowski
I know I cannot do a standard conditional in a macro, but I was counting really on some interesting syntax that reduces to a NOOP if its expended with NULL, and to a declaration if it's something else... But yeah - even that might be not possible. I'll try generating externally.
viraptor
-1 because our statement is wrong. In the Boost preprocessor library they have those type of conditional macros that depending on a macro argument can do different things, eg BOOST_PP_EXPR_IF.
Jens Gustedt
So would it do a NULL check? Because the source here http://www.boost.org/doc/libs/1_41_0/boost/preprocessor/logical/bool.hpp suggests it really does need the condition to be evaluated by preprocessor to a number from 0 to 256. BOOST_PP_EXPR_IIF is a pretty clever thing, though.
Piotr Kalinowski
+1  A: 

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.

Nathon
A: 

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.

Jens Gustedt
Any particular reason to downvote? (Currently +1 -2)
Jens Gustedt
I downvoted, because you made claims without any examples or references. I don't know whether boost does what I need with preprocessing or not, but it's a too large piece of code to look through without any specific pointers. If you can show an example which could solve this problem, it would be useful - otherwise it's like saying "yeah, it's possible, but you'll have to find it yourself over there in that big pile of cryptic library's code" - not very helpful.
viraptor
@viraptor: I didn't give examples, since it really is complicated (as I said) and would not fit into an appropriate answer here. (Ok, I didn't give a reference to boost, but I guess you would be able to find that.) Second, the preprocessor part of boost is not so cryptic, I find. It has exactly the conditionals that your are asking for in the answer that you accepted. And then just downvoting without giving a reason or asking for more information ... isn't much helpful either. Merely rude, I'd say by somebody who asked for help.
Jens Gustedt