Best way to handle opening brace when using a macro to create functions

Viewed 55

Edit: Since the replies seem to be focusing on the void* to typed* conversion, I've changed the example to something a bit more concrete.

I have a bunch of functions that all follow the same pattern:

int prefix_name(void *p) {
  my_type *t = (my_type *)p;
  <possibly other common lines>

  <function-specific code>
}

static int mod_name(lua_State *L) {
  lua_pushlightuserdata(L, (void *)&KEY);
  lua_gettable(L, LUA_REGISTRYINDEX);
  typed *t = lua_touserdata(L, -1);

  <function-specific code>
}

To reduce typing and typos, I created a simple macro:

#define API_FUNCTION(name) static int mod_ ## name(lua_State *L) {\
  lua_pushlightuserdata(L, (void *)&KEY);\
  lua_gettable(L, LUA_REGISTRYINDEX);\
  typed *t = lua_touserdata(L, -1);

so I can then just write each function as

API_FUNCTION(name)
  <function-specific code>
}

This works well, but because the opening brace is in the macro, this breaks the brace-matching function in my editor. Is there something I could change in the macro so I could write

API_FUNCTION(name) {
  <function-specific code>
}

and have things work as intended?

One possible alternative might be to define the macro as

API_FUNCTION(name, ...) int prefix_ ## name(void *p) {\
  my_type *t = (my_type*)p;\
  <possibly other common lines>
  __VA_ARGS__
}

and then call it as

API_FUNCTION(name,
  <function-specific code>
)

which at first glance does appear to work, but I don't like the way it looks and it also makes the preprocessor output much larger.

Edit 2: based on Orel's code, I suppose something like this would work, though it's rather ugly and means an extra function call:

#define API_FUNCTION(name) static int mod_ ## name ## _internal(lua_State *L, typed *t);\
static int mod_ ## name(lua_State *L) {\
  lua_pushlightuserdata(L, (void *)&KEY);\
  lua_gettable(L, LUA_REGISTRYINDEX);\
  typed *t = lua_touserdata(L, -1);\
  return mod_ ## name ## _internal(L,t); \
} \
static int mod_ ## name ## _internal(lua_State *L, typed *t)
2 Answers

because the opening brace is in the macro, this breaks the brace-matching function in my editor. Is there something I could change in the macro so I could write

API_FUNCTION(name) {
  <function-specific code>
}

and have things work as intended?

No, not exactly like that, because the opening brace needs to appear between two parts of the macro's replacement text. It can definitely be part of the replacement text itself, as you already know, but if you want to express it separately from the macro then the macro's replacement text will go either all before it or all after it.

You could, however, split the macro into two:

#define API_FUNCTION(name) static int mod_ ## name(lua_State *L)

#define API_FUNCTION_DECLARATIONS \
    lua_pushlightuserdata(L, (void *)&KEY);\
    lua_gettable(L, LUA_REGISTRYINDEX);\
    typed *t = lua_touserdata(L, -1)

Then you might write

API_FUNCTION(name) {
    API_FUNCTION_DECLARATIONS;

    <function-specific code>
}

That's not quite what you asked for, but it's as close as you can come.

Updated with new needs.

Create definition add an intermediate function to call function with all arguments, you can add what you need in GENERIC_FIRST_LINES

#include <stdio.h>
#include <stdlib.h>


typedef struct my_type {
    int foo;
    int bar;
} my_type;

#define GENERIC_FN(name) prefix_##name

#define GENERIC_FIRST_LINES(name)               \
{                                               \
    _prefix_##name(12, t);                      \
}                                               \
int _prefix_##name(int L, my_type *t)

#define GENERIC(name)                                  \
    static int _prefix_##name(int L, my_type *t);      \
    static int GENERIC_FN(name)(my_type *t)            \
    GENERIC_FIRST_LINES(name)

GENERIC(toto) {
       return t->foo;
}

int main(void)
{
    my_type t;
    t.foo = 1;
    t.bar = 2;

    printf("%d \n", prefix_toto((void *) &t));
    return 0;
}

Related