如何使用作为参数传递给lua C函数的表?

我将用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}} }
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时,熟悉虚拟堆栈非常重要 – 所有重要的语言边界交互都发生在那里。 查看您的代码段,看起来您并没有正确地将数据整理到C语言。

在编写lua C函数时,你基本上必须做3件事:

  • 将输入lua数据转换为可在C中使用的内容。
  • 执行处理或function需要做的任何事情。
  • 转换并返回输出结果(如果有)返回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*函数代替并提供默认值。 例如,如果fuzzyignoreColor是可选的:

  // ... 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而使用默认值。