【问题标题】:Best way to handle opening brace when using a macro to create functions使用宏创建函数时处理左大括号的最佳方法
【发布时间】:2020-05-19 20:01:03
【问题描述】:

编辑:由于回复似乎集中在 void* 到 typed* 的转换,我已将示例更改为更具体的内容。

我有一堆函数都遵循相同的模式:

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>
}

为了减少打字和拼写错误,我创建了一个简单的宏:

#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);

所以我可以把每个函数写成

API_FUNCTION(name)
  <function-specific code>
}

这很好用,但是因为左大括号在宏中,这会破坏我的编辑器中的大括号匹配功能。有什么我可以在宏中改变的东西,所以我可以写

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

并让事情按预期工作?

一种可能的替代方法是将宏定义为

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

然后将其称为

API_FUNCTION(name,
  <function-specific code>
)

乍一看确实可行,但我不喜欢它的外观,而且它还使预处理器输出更大。

编辑 2:基于 Orel 的代码,我想这样的东西会起作用,虽然它相当丑陋并且意味着额外的函数调用:

#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)

【问题讨论】:

  • 为此使用函数怎么样?除非您发布实际代码,否则我个人无法真正帮助您解决宏问题。
  • 可能有点难看,但您可以定义一个结束函数宏:#define API_FUNCEND } 并使用它来代替显式右大括号 - 这应该让您的编辑器满意。 (您甚至可以在该宏中包含任何常见的return 代码?)
  • 编写一个以my_type *为参数的函数并创建调用它的宏。我真的不明白你用这种宏赢得了什么。

标签: c macros


【解决方案1】:

因为左大括号在宏中,这会破坏 我的编辑器中的大括号匹配功能。有什么我可以 更改宏,以便我可以编写

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

并让事情按预期工作?

不,不完全一样,因为左大括号需要出现在宏的替换文本的两个部分之间。正如您已经知道的,它绝对可以是替换文本本身的一部分,但是如果您想将它与宏分开表达,那么宏的替换文本将要么全部放在它之前,要么全部放在它之后。

不过,您可以将宏一分为二:

#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)

那你可以写

API_FUNCTION(name) {
    API_FUNCTION_DECLARATIONS;

    <function-specific code>
}

这不是你所要求的,但它已经尽可能接近了。

【讨论】:

    【解决方案2】:

    根据新需求更新。

    创建定义添加一个中间函数来调用所有参数的函数,您可以在 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;
    }
    
    

    【讨论】:

    • 这将负责参数转换,但不负责其他常见代码行。我会用一个更具体的例子来更新原来的问题。
    • @Jochen 我已经更新它以向函数添加更多参数
    猜你喜欢
    • 1970-01-01
    • 2013-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-28
    • 1970-01-01
    • 2018-02-18
    • 2013-11-11
    相关资源
    最近更新 更多