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

Sug*_*uge 4 c lua lua-table

我将用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}}
}

gre*_*olf 12

使用Lua C API时,熟悉虚拟堆栈非常重要 - 所有重要的语言边界交互都发生在那里.查看您的代码段,看起来您并没有正确地将数据整理到C语言.

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

  • 将输入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;
}
Run Code Online (Sandbox Code Playgroud)

请注意,我们必须保持imagePath堆栈,因为我们持有const char *它.弹出该字符串会失效,*imagePath因为lua可能会收集它.

或者,您可以将返回的字符串复制luaL_checkstring到另一个缓冲区中.在这种情况下弹出字符串是可以的,因为我们不再指向lua拥有的内部缓冲区.

编辑:如果表中的某些键是可选的,则可以luaL_opt*改为使用这些函数并提供默认值.例如,if 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
  // ...
Run Code Online (Sandbox Code Playgroud)

因此,如果调用代码为键提供了无意义的值,则仍会引发错误.OTOH,如果它不存在那么值是nil,而是使用默认值.