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

我将要用C语言实现一个函数,并且这个函数将会被Lua脚本调用。

这个函数应该以一个Lua表作为参数,所以我应该读取表中的字段。我试图像下面一样做,但是当我运行它时,我的函数会崩溃。有人能帮我找到问题吗?


/*
 function findImage(options)
    imagePath = options.imagePath
    fuzzy = options.fuzzy
    ignoreColor = options.ignoreColor;

 end

 呼叫範例:

  findImage {imagePath="/var/image.png", fuzzy=0.5, ignoreColor=0xffffff}

 */

// 用C语言实现函数
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;   // 我希望返回一个Lua表格,比如: {{11, 12}, {21, 22}, {31, 32}}
}
点赞
用户234175
用户234175

在Lua C API中工作时,熟悉使用虚拟栈很重要——所有重要的语言边界交互都发生在那里。看看你的代码片段,似乎你没有正确地将数据编组到C中。

编写Lua C函数时,你基本上需要完成三件事:

  • 将输入的Lua数据转换为C中可以使用的东西。
  • 执行处理或函数需要执行的任何操作。
  • 如果有任何输出结果,则将其转换并返回给Lua。

以下是findImgProxy应该是什么样子的示例:

static int findImgProxy(lua_State *L)
{
  // 抛弃传入的任何额外参数
  lua_settop(L, 1);
  luaL_checktype(L, 1, LUA_TTABLE);

  // 现在从表中获取数据
  // 通过将值放入栈中 '解包' 表,然后将这些栈值转换为适当的C类型。
  lua_getfield(L, 1, "imagePath");
  lua_getfield(L, 1, "fuzzy");
  lua_getfield(L, 1, "ignoreColor");
  // 现在栈中有以下内容:
  //   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);
  // 我们可以弹出模糊度和忽略颜色从栈上,
  // 因为我们已经用值取到了它们
  lua_pop(L, 2);

  // 进行函数处理
  // ...

  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); // 如果缺少fuzzy,则默认为0.0
  int ignoreColor = luaL_optint(L, -1, 0);      // 如果缺少ignoreColor,则默认为0
  // ...

因此,如果调用代码为键提供了无意义的值,则仍会引发错误。另一方面,如果缺少它,则值为nil,并使用提供的默认值。

2013-08-28 04:38:26