如何处理作为参数传递给 lua C 函数的表? [英] How to work with tables passed as an argument to a lua C function?

查看:16
本文介绍了如何处理作为参数传递给 lua C 函数的表?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我打算用 C 语言实现一个函数,该函数将被 Lua 脚本调用.

这个函数应该接收一个lua表作为参数,所以我应该读取表中的字段.我尝试像下面那样做,但是当我运行它时我的函数崩溃了.谁能帮我找到问题?

<前><代码>/*函数 findImage(选项)imagePath = options.imagePath模糊 = options.fuzzyignoreColor = options.ignoreColor;结尾调用示例:findImage {imagePath="/var/image.png",fuzzy=0.5,ignoreColor=0xffffff}*///用C语言实现函数静态 int findImgProxy(lua_State *L){luaL_checktype(L, 1, LUA_TTABLE);lua_getfield(L, -1, "imagePath");如果(!lua_isstring(L,-1)){错误();}const char * imagePath = lua_tostring(L, -2);lua_pop(L, 1);lua_getfield(L, -1, "模糊");如果(!lua_isnumber(L,-1)){错误();}浮动模糊 = lua_tonumber(L, -2);lua_getfield(L, -1, "ignoreColor");如果(!lua_isnumber(L,-2)){错误();}浮动忽略颜色 = lua_tonumber(L, -2);...返回 1;}

把一个表从 C 返回到 Lua 怎么样:

<前><代码>结构点{整数 x, y;}typedef 点 点;静态 int returnImageProxy(lua_State *L){点点[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);}返回 1;//我想返回一个 Lua 表,如:{{11, 12}, {21, 22}, {31, 32}}}

解决方案

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

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

  • 将输入的 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, "模糊");lua_getfield(L, 1, "ignoreColor");//堆栈现在有以下内容://1 = {imagePath="/var/image.png",fuzzy=0.5, ignoreColor=0xffffff}//-3 = "/var/image.png"//-2 = 0.5//-1 = 0xffffffconst char *imagePath = luaL_checkstring(L, -3);双模糊 = luaL_checknumber(L, -2);int ignoreColor = luaL_checkint(L, -1);//我们可以从堆栈中弹出模糊并忽略颜色//因为我们是按值获取的lua_pop(L, 2);//做函数处理//...返回 1;}

请注意,我们必须将 imagePath 保留在堆栈中,因为我们将 const char * 保存在堆栈中.弹出该字符串会使 *imagePath 无效,因为 lua 可能会收集它.

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

如果表中的某些键是可选的,您可以改用 luaL_opt* 函数并提供默认值.例如,如果 fuzzyignoreColor 是可选的:

//...const char *imagePath = luaL_checkstring(L, -3);双模糊 = luaL_optnumber(L, -2, 0.0);//如果没有模糊,则默认为 0.0int ignoreColor = luaL_optint(L, -1, 0);//如果没有 ignoreColor 默认为 0//...

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

I'm going to implement a function with C language and which will be called by Lua script.

This function should receive a lua table as the argument, so I should read the fields in the table.I try to do like below, but my function is crashing when I run it. Can anyone help my find the problem?


/*
 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;
}

How about return a table from C to 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}}
}

解决方案

When working with the Lua C API it's important to get comfortable working with the virtual stack -- all the important language boundary interactions happen there. Looking at your code snippet, it does not look like you're marshaling the data properly over to C.

When writing a lua C function you basically have to do 3 things:

  • Convert input lua data into something you can work with in C.
  • Perform the processing or whatever the function needs to do.
  • Convert and return the output result if any back to lua.

As an example, here's what your findImgProxy should look like:

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;
}

Note that we must keep imagePath on the stack since we're holding a const char * to it. Popping that string off would invalidate *imagePath since lua might collect it.

Alternatively, you can copy the string returned by luaL_checkstring into another buffer. Popping the string off in this case is ok since we're no longer pointing to an internal buffer owned by lua.

Edit: If some of the keys in the table are optional, you can use the luaL_opt* functions instead and provide defaults. For example, if fuzzy and ignoreColor are optional:

  // ...
  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
  // ...

So if the calling code provides a nonsensical value for a key, this will still raise an error. OTOH, if it's absent then the value is nil and the default provided is used instead.

这篇关于如何处理作为参数传递给 lua C 函数的表?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆