Lua c API 创建后更改库

Lua c API change library after creation

我正在尝试使用 C API 在 Lua 中包装 ncurses。我正在使用 stdscr 指针:在调用 initscr 之前这是 NULL,根据我的绑定设计,initscr 是从 Lua 调用的。所以在驱动函数中我这样做:

// Driver function
LUALIB_API int luaopen_liblncurses(lua_State* L){
    luaL_newlib(L, lncurseslib);

    // This will start off as NULL
    lua_pushlightuserdata(L, stdscr);
    lua_setfield(L, -2, "stdscr");

    lua_pushstring(L, VERSION);
    lua_setglobal(L, "_LNCURSES_VERSION");
    return 1;
}

这按预期工作。当我需要修改stdscr时,麻烦就来了。 initscr 绑定如下:

/*
** Put the terminal in curses mode
*/
static int lncurses_initscr(lua_State* L){
    initscr();
    return 0;
}

我需要修改库中的 stdscr 使其不再为空。 Lua 端的示例代码:

lncurses = require("liblncurses");
lncurses.initscr();
lncurses.keypad(lncurses.stdscr, true);
lncurses.getch();
lncurses.endwin();

但是,lncurses.stdscr 是 NULL,所以它本质上是 运行 keypad(NULL, true);

的 c 等价物

我的问题是,如何在创建库后修改 Lua 中的库值?

您可以使用 registry.

Lua provides a registry, a predefined table that can be used by any C code to store whatever Lua values it needs to store. The registry table is always located at pseudo-index LUA_REGISTRYINDEX. Any C library can store data into this table, but it must take care to choose keys that are different from those used by other libraries, to avoid collisions. Typically, you should use as key a string containing your library name, or a light userdata with the address of a C object in your code, or any Lua object created by your code. As with variable names, string keys starting with an underscore followed by uppercase letters are reserved for Lua.

创建时在注册表中存储对模块 table 的引用。

LUALIB_API int luaopen_liblncurses(lua_State* L) {
    luaL_newlib(L, lncurseslib);

    // This will start off as NULL
    lua_pushlightuserdata(L, stdscr);
    lua_setfield(L, -2, "stdscr");

    lua_pushstring(L, VERSION);
    lua_setglobal(L, "_LNCURSES_VERSION");

    // Create a reference to the module table in the registry
    lua_pushvalue(L, -1);
    lua_setfield(L, LUA_REGISTRYINDEX, "lncurses");
    return 1;
}

然后当您 initscr 更新字段时。

static int lncurses_initscr(lua_State* L) {
    initscr();

    // Update "stdscr" in the module table
    lua_getfield(L, LUA_REGISTRYINDEX, "lncurses");
    lua_pushlightuserdata(L, stdscr);
    lua_setfield(L, -2, "stdscr");
    return 0;
}