c - Lua 将句柄传递给使用 newlib 创建的函数

标签 c json lua

我正在使用luaL_newlib(luaState, afbFunction),其中afbFunction是一个静态luaL_Reg数组。不幸的是,luaL_Reg只支持两个字段:namefunc。因此,无法将句柄传递给函数并实现类似以下内容:

static const luaL_Reg afbFunction[] = {
    {"notice" , LuaPrintMsg, MSG_NOTICE},
    {"info"   , LuaPrintMsg, MSG_INFO},
    {"warning", LuaPrintWar, MSG_WARN},
    {NULL, NULL}  /* sentinel */
};

我之所以不使用像 Lua 函数那样多的 C 入口点,有两个动机:

  1. 我有一个用于所有 C 函数的通用包装器来处理输入/输出 参数值从 Lua(表)到 C(jsonc)。
  2. 接口(interface)的 Lua 函数数量来自配置文件,并且可以更改而无需重建代码。长话短说,配置文件有一个 sharelib 路径,后面是要公开的函数列表。

有人有办法为多个 Lua 函数提供唯一的 C 入口点吗?当使用 luaL_newlib() 时,C 函数接收 lib 表作为第二个参数,但它似乎接收完整的表而不是相应的条目,甚至无法测试标签。

最佳答案

使用上值!

如果您不使用 luaL_newlib (这是一个宏,定义为...

#define luaL_newlib(L,l)  \
  (luaL_checkversion(L), luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))

...) 但显式调用 luaL_setfuncs ,您可以使每个函数具有一定数量的上值。用 nil 初始化所有这些就可以了。 ,您可以稍后修补它们。虽然您无法扩展 luaL_Reg对于额外的字段,您可以定义额外的 struct并为其他参数设置一个单独的数组。

最小示例实现(可能需要更多错误检查):

(应按原样复制和粘贴,文本 block 应成为注释)


#include <lua.h>
#include <lauxlib.h>
/*

首先,定义一个struct首先是函数的名称,然后是您需要的任何内容。此示例仅使用字符串,但您可以使用 int , void* ,...甚至有多个值。

*/
typedef struct xlua_uvinfo {
    const char *name;  /* this is how we identify the functions */
    const char *uv;  /* this can change arbitrarily */
} xlua_uvinfo;
/*

然后我们将有一个函数来修补堆栈上的 libtable 以放入真正的上值数据。您需要调整推送的字段的类型 ( lua_pushX )、顺序和/或名称。

请注意,当我们通过名称识别函数时,并非所有函数都需要获取上值。 (因此,您可以在 luaL_Reg 中包含普通函数,这些函数最终会得到此处不会填充的虚拟上值槽。)

*/
static void setupvalues( lua_State *L, const xlua_uvinfo *l ) {
    for (; l->name != NULL; l++) {
        /* get the function by name */
        if (lua_getfield( L, -1, l->name ) == LUA_TFUNCTION) {
            /* this needs to change according to what you have in the struct */
            lua_pushstring( L, l->uv );
            lua_setupvalue( L, -2, 1 );
        }
        /* pop the function */
        lua_pop( L, 1 );
    }
}
/*

这是您的函数的虚拟实现。我使用字符串前缀 - 这很容易调试/检查。

*/
#define MSG_NOTICE "NOTE"
#define MSG_INFO "INFO"
#define MSG_WARN "WARN"

static int LuaPrintMsg( lua_State *L ) {
   const char *prefix = lua_tostring( L, lua_upvalueindex(1) );
   printf( "%s: %s\n", prefix, lua_tostring( L, 1 ) );
   return 0;
}

/* plain luaL_Reg array */
static const luaL_Reg afbFunction[] = {
    {"notice" , LuaPrintMsg},
    {"info"   , LuaPrintMsg},
    {"warning", LuaPrintMsg},
    {NULL, NULL}
};
/*

现在改变的部分是:为上值添加一个额外的数组,然后调整 luaopen_X功能。

*/
/* extra upvalue array (must also be terminated by { NULL, NULL } !) */
static const xlua_uvinfo afbUpvalues[] = {
    {"notice" , MSG_NOTICE},
    {"info"   , MSG_INFO},
    {"warning", MSG_WARN},
    {NULL, NULL}
};

int luaopen_foo( lua_State *L ) {
    /* as mentioned above, we can't use `luaL_newlib`, expand manually */
    luaL_checkversion( L );
    /* create the empty table, pre-allocated to the right size */
    luaL_newlibtable( L, afbFunction );
    /* now push a dummy upvalue (more if you add extra upvalues!) */
    lua_pushnil( L );
    /* register the functions, giving 1 upvalue to each */
    luaL_setfuncs( L, afbFunction, 1 );
    /* now set the actual upvalues */
    setupvalues( L, afbUpvalues );
    return 1;
}

如果将其另存为 foo.c ,编译为(在 Linux 上)gcc -shared -fPIC -o foo.so foo.c然后运行lua -l foo ,您将获得所需的行为:

foo.info "foo"
--> INFO: foo
foo.notice "bar"
--> NOTE: bar
foo.warning "baz"
--> WARN: baz

关于c - Lua 将句柄传递给使用 newlib 创建的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45699950/

相关文章:

当定义包含参数时调用不带参数的函数

arrays - 将列表作为参数传递给c中的函数

java - 如果我想传递json,如何注释jersey方法?

lua - 如何指定 lua 模式匹配尝试中的迭代次数?

C链表进程返回255(0xFF)执行时间2.144s

json - 世博会中的动态本地镜像?

javascript - 如何在 JavaScript 中解码 JSON?

lua - 尝试将数字与字符串进行比较(Lua)

lua - 我可以检测到值刚刚分配给 Lua 中的表的时刻吗?

c - 对数组进行排序,使偶数先降序出现,然后赔率升序出现