将C语言中的整数绑定到Lua全局变量。

在 C 语言中,我想要调用一个 Lua 函数 myFunction(),该函数使用了一个全局变量 x。我想直接将 C 语言中的一个整数变量注册为这个全局变量 x。

大概是这样:

demo.lua:

function myFunction()
  return x + 3
end

demo.c:

int x = 0;
lua_bindglob(L, "x", &x);

for (x = 0; x < 100; ++x)
{
  lua_getglobal(L, "myFunction");

  // 在这里调用函数,它应该会求出 x 的当前值(在 C 语言中)
  lua_pcall(L, 0, 1, 0);
  int result = lua_tonumber(L, -1);

  lua_pop(L, 1);
}

我知道我可以通过以下方式修改 Lua 中的全局变量:

lua_pushnumber(L, 3);
lua_setglobal(L, "x");

但我需要有一种更直接/更快的方法来实现这一点。我得到了一个提示,说 LUA ligthuserdata 可能会对此有所帮助,但我找不到任何关于普通变量的示例。

编辑: 由于我从基准测试中获取表达式,所以我不想改变它们: 见这里的示例:

点赞
用户734069
用户734069

最好的方法就是创建一个 __call 元方法,通过这个方法可以创建一个拥有正常 userdata(非轻量级)的函数,用于获取/设置 C 值。

所以你的函数如下所示:

function myFunction()
  return x() + 3
end

你可以定义操作元方法,使得像 x + 3 这样的操作能够正常工作,但是没有办法让一个裸的 x 表达式返回你想要的值。

要设置值,可以这么做:

x(3)

不能像 x = 3 那样使用,因为这会始终覆盖已有的值。

使用 __newindex__index 元方法也不行,因为你希望这个变量是_全局_的。

或者,你可以使用 LuaJIT 和其 FFI 接口。

2016-01-13 13:50:56
用户3677376
用户3677376

如果您只有一些从 Lua 访问的 C 变量,您可以在全局表上设置一个具有 __index__newindex 元方法的元表。当访问(get 或 set)不存在的全局变量时,这些元方法被调用,您需要查看这些元方法的第二个参数(变量名)来确定该怎么做。

导出单个变量的模块的示例代码:

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

static int x = 0;

static int myvar_index(lua_State* L) {
    char const* key = lua_tostring(L, 2);
    if (key != NULL && strcmp(key, "x") == 0)
        lua_pushinteger(L, x);
    else
        lua_pushnil(L);
    return 1;
}

static int myvar_newindex(lua_State* L) {
    char const* key = lua_tostring(L, 2);
    if (key != NULL && strcmp(key, "x") == 0) {
        lua_Integer i = luaL_checkinteger(L, 3);
        if (i > INT_MAX || i < INT_MIN)
            luaL_error(L, "variable value out of range");
        x = i;
    } else
        lua_rawset(L, 1);
    return 0;
}

int luaopen_myvar(lua_State* L) {
    luaL_Reg const metamethods[] = {
        { "__index", myvar_index },
        { "__newindex", myvar_newindex },
        { NULL, NULL }
    };
#if LUA_VERSION_NUM < 502
    lua_pushvalue(L, LUA_GLOBALSINDEX);
    lua_newtable(L);
    luaL_register(L, NULL, metamethods);
#else
    lua_pushglobaltable(L);
    luaL_newlib(L, metamethods);
#endif
    lua_setmetatable(L, -2);
    return 0;
}

您要导出的 C 变量越多,元方法实现就越复杂,最好使用其他建议的方法。

还要注意,全局表是一个共享资源,所以您必须避免/处理与其他修改其元表的代码发生冲突。 (即可重用的模块不应修改共享资源-但我想同样适用于 C 中的全局变量...)

2016-01-13 17:06:27