Lua 共享上值在 C 中的实例

让我们创建一个简单的 C 模块,用于 Lua 5.3 中的全局 int:

static int l_test(lua_State *L){
    int Global = lua_tointeger(L, lua_upvalueindex(1));
    Global++;
    lua_pushinteger(L, Global);
    lua_pushvalue(L, -1);
    lua_replace(L, lua_upvalueindex(1));
    //lua_pushnumber(L, Global);
    return 1;
}

static int l_anotherTest(lua_State *L){
    int Global = lua_tointeger(L, lua_upvalueindex(1));
    Global++;
    Global++;
    lua_pushinteger(L, Global);
    lua_pushvalue(L, -1);
    lua_replace(L, lua_upvalueindex(1));
    //lua_pushnumber(L, Global);
    return 1;
}

static const struct luaL_Reg testLib [] = {
    {"test", l_test},
    {"anotherTest", l_anotherTest},
    {NULL, NULL}
};

int luaopen_testLib(lua_State *L){
    luaL_newlibtable(L, testLib);
    lua_pushinteger(L, 1);
    luaL_setfuncs(L, testLib, 1) ;
    return 1;
}

这几乎可行,但当我像这样从 Lua 调用这两个函数时:

local testLib = require "testLib"
print(testLib.test())
print(testLib.anotherTest())

第二个打印应该是 4,但它输出了 3。 我还做错了什么?

点赞
用户3677376
用户3677376

C 闭包的 upvalue 不是共享的,只有 Lua 闭包的 upvalue 是共享的。每个 C 闭包都包含自己的 upvalue(参见 这里)。如果要为两个或多个 C 闭包共享值,则在所有这些闭包中使用单个共同的表作为 upvalue 并将共享的值放在其中,或者改用注册表来存储共享数据。

如下所示,可以实现所需的操作:

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

/* getint 和 setint 只能从具有共享表作为 upvalue 1 的 Lua C 函数中调用 */

static int getint(lua_State *L){
  int v = 0;
  lua_getfield(L, lua_upvalueindex(1), "myint");
  v = lua_tointeger(L, -1);
  lua_pop(L, 1); /* 从堆栈中移除整数 */
  return v;
}

static void setint(lua_State *L, int v){
  lua_pushinteger(L, v);
  lua_setfield(L, lua_upvalueindex(1), "myint");
}

static int l_test(lua_State *L){
    int Global = getint(L);
    Global++;
    setint(L, Global);
    lua_pushinteger(L, Global);
    return 1;
}

static int l_anotherTest(lua_State *L){
    int Global = getint(L);
    Global++;
    Global++;
    setint(L, Global);
    lua_pushinteger(L, Global);
    return 1;
}

static const struct luaL_Reg testLib [] = {
    {"test", l_test},
    {"anotherTest", l_anotherTest},
    {NULL, NULL}
};

int luaopen_testLib(lua_State *L){
    luaL_newlibtable(L, testLib);
    lua_newtable(L);
    lua_pushinteger(L, 1);
    lua_setfield(L, -2, "myint");
    luaL_setfuncs(L, testLib, 1);
    return 1;
}
2017-09-03 12:29:49