Reputation: 2897
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}}
}
Upvotes: 5
Views: 13119
Reputation: 20838
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:
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.
Upvotes: 14