我要用C语言实现一个函数,这个函数会被Lua脚本调用。
这个函数应该接收一个 lua 表作为参数,所以我应该读取表中的字段。我尝试像下面那样做,但是当我运行它时我的函数崩溃了。谁能帮我找出问题所在?
/*
function findImage(options)
imagePath = options.imagePath
fuzzy = options.fuzzy
ignoreColor = options.ignoreColor;
end
Call Example:
findImage {imagePath="/var/image.png", fuzzy=0.5, ignoreColor=0xffffff}
*/
// implement the function by C language
static int findImgProxy(lua_State *L)
{
luaL_checktype(L, 1, LUA_TTABLE);
lua_getfield(L, -1, "imagePath");
if (!lua_isstring(L, -1)) {
error();
}
const char * imagePath = lua_tostring(L, -2);
lua_pop(L, 1);
lua_getfield(L, -1, "fuzzy");
if (!lua_isnumber(L, -1)) {
error();
}
float fuzzy = lua_tonumber(L, -2);
lua_getfield(L, -1, "ignoreColor");
if (!lua_isnumber(L, -2)) {
error();
}
float ignoreColor = lua_tonumber(L, -2);
...
return 1;
}
如何将表从 C 返回到 Lua:
struct Point {
int x, y;
}
typedef Point Point;
static int returnImageProxy(lua_State *L)
{
Point points[3] = {{11, 12}, {21, 22}, {31, 32}};
lua_newtable(L);
for (int i = 0; i 3; i++) {
lua_newtable(L);
lua_pushnumber(L, points[i].x);
lua_rawseti(L, -2, 0);
lua_pushnumber(L, points[i].y);
lua_rawseti(L, -2, 1);
lua_settable(L,-3);
}
return 1; // I want to return a Lua table like :{{11, 12}, {21, 22}, {31, 32}}
}
最佳答案
在使用 Lua C API 时,重要的是要熟悉虚拟堆栈的工作——所有重要的语言边界交互都发生在那里。查看您的代码片段,您似乎没有将数据正确编码(marshal)至 C。
编写 lua C 函数时,您基本上必须做 3 件事:
- 将输入的 lua 数据转换为可以在 C 中使用的数据。
- 执行处理或函数需要执行的任何操作。
- 将输出结果转换并返回给lua。
例如,您的 findImgProxy
应该如下所示:
static int findImgProxy(lua_State *L)
{
// discard any extra arguments passed in
lua_settop(L, 1);
luaL_checktype(L, 1, LUA_TTABLE);
// Now to get the data out of the table
// 'unpack' the table by putting the values onto
// the stack first. Then convert those stack values
// into an appropriate C type.
lua_getfield(L, 1, "imagePath");
lua_getfield(L, 1, "fuzzy");
lua_getfield(L, 1, "ignoreColor");
// stack now has following:
// 1 = {imagePath="/var/image.png", fuzzy=0.5, ignoreColor=0xffffff}
// -3 = "/var/image.png"
// -2 = 0.5
// -1 = 0xffffff
const char *imagePath = luaL_checkstring(L, -3);
double fuzzy = luaL_checknumber(L, -2);
int ignoreColor = luaL_checkint(L, -1);
// we can pop fuzzy and ignoreColor off the stack
// since we got them by value
lua_pop(L, 2);
// do function processing
// ...
return 1;
}
请注意,我们必须将 imagePath
保存在堆栈中,因为我们为它保存了一个 const char *
。弹出该字符串将使 *imagePath
无效,因为 lua 可能会收集它。
或者,您可以将 luaL_checkstring
返回的字符串复制到另一个缓冲区中。在这种情况下弹出字符串是可以的,因为我们不再指向 lua 拥有的内部缓冲区。
编辑:如果表中的某些键是可选的,您可以改用luaL_opt*
函数并提供默认值。例如,如果 fuzzy
和 ignoreColor
是可选的:
// ...
const char *imagePath = luaL_checkstring(L, -3);
double fuzzy = luaL_optnumber(L, -2, 0.0); // defaults to 0.0 if no fuzzy
int ignoreColor = luaL_optint(L, -1, 0); // defaults to 0 if no ignoreColor
// ...
因此,如果调用代码为键提供了一个无意义的值,这仍然会引发错误。 OTOH,如果不存在,则值为 nil
并使用提供的默认值。
关于c - 如何使用作为参数传递给 lua C 函数的表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18478379/