5

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

2
  • "something wrong" What is wrong? What do you expect it to do and what is it doing that isn't correct? Commented Aug 28, 2013 at 2:21
  • I want to read the lua table in C function, but it's crashed, I'm still finding the problem.So I want someone can help me check if the way right I used on. Commented Aug 28, 2013 at 2:26

1 Answer 1

14

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.

Sign up to request clarification or add additional context in comments.

17 Comments

@ greatwolf thank you very much, I've never got an answer so clear and helpful like yours.Generally I've understood.But I have another problem, I should return a table from the C function to lua, but my code(added above) doesn't work, could you have a look?Thank you so much.
And if the key's number of the argument table is not fixed, the table may be {imagePath="/var/q.png"} or may be {imagePath="/var/q.png", fuzzy=1.0} or may be {imagePath="/var/q.png", ignoreColor=0xffffff}.How can I get the values?
@Suge if some of the keys are optional you can use luaL_opt* functions to get them.
@Suge I've added an example for this.
Thank you very much, I've got it.Could you take a look at the code above I use to return a table from C function?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.