2

I need to define an event handler and then to add it to an array of handlers at a certain index. The handler will never be called by its real name, so I want to handle both the definition and the assignment in one place. A good solution would look like this:

MAKE_HANDLER(evet_code, my_event) {
    //handle the event
}

My naive solution was to have this expand into

void on_my_event(event* ev);
array_of_handlers[event_code] = &on_my_event;
void on_my_event(event* ev) {
    //handle the event
}

Obviously this doesn't work, since an assignment cannot occur in global scope (except for initialization by constant). I am aware that I could have one macro define the function and another assign it in main, however this would be a duplication of information and very tedious to work with, when I have many handlers. What other solutions are there?

Karolis Juodelė
  • 3,708
  • 1
  • 19
  • 32

2 Answers2

1

[...] since an assignment cannot occur in global scope [...]

You could use a constructor (search in this page) to run the assignment code on startup, without cluttering your main function:

void on_my_event(event* ev);
void on_my_event_constructor(void)  __attribute__((constructor));
void on_my_event_constructor(void) {
  array_of_handlers[event_code] = &on_my_event;
}
void on_my_event(event* ev) {
    //handle the event
}

Though this is in no way portable. (But works in GCC and clang, and apparently with some hacking in MSVC, too.)

Community
  • 1
  • 1
Daniel Jour
  • 15,896
  • 2
  • 36
  • 63
1

You can create a file, for example handlers.inc and put all your macro calls there:

MAKE_HANDLER(a,b)
MAKE_HANDLER(c,d)
MAKE_HANDLER(e,f)

When you use it, do the following:

#define MAKE_HANDLER(evet_code, my_event) .....
#include "handlers.inc"
#undef MAKE_HANDLER

define MAKE_HANDLER in the global scope just to the declarations and definitions. And inside the initialization function do just the initialization.

wimh
  • 15,072
  • 6
  • 47
  • 98
  • My include file would contain `MAKE_HANDLER(a,b) { and some code }` instead. I guess in main I could do `#define MAKE_HANDLER(a,b) handlers[a]=...; if (false)` to ignore the function bodies... – Karolis Juodelė Jul 25 '15 at 11:58
  • If you really need code there, it will become trickier, although still possible. If you add parentheses around the code, it can be a macro parameter. Or you can surround the code with something like `#ifdef IMPLEMENTATION`. But it might be easier if you generate your code. – wimh Jul 25 '15 at 12:32