How to work with tables passed as an argument to a lua C function?
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.
Related videos on Youtube

Suge
Updated on September 16, 2022Comments
-
Suge 3 months
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}} }
-
Suge over 9 years@ 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.
-
Suge over 9 yearsAnd 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?
-
greatwolf over 9 years@Suge if some of the keys are optional you can use
luaL_opt*
functions to get them. -
greatwolf over 9 years@Suge I've added an example for this.
-
Suge over 9 yearsThank 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?
-
greatwolf over 9 years@Suge you're doing
lua_settable
on the wrong index.lua_rawseti
pops a value off so the outter table is at index -2. -
greatwolf over 9 years@Suge try
lua_rawseti(L, -2, i + 1);
instead -
lhf over 9 yearsI think it'd be clearer to use
lua_getfield(L,1, ...)
for all 3 calls. -
Suge over 9 yearsHow to use
lua_getfield(L,1, ...)
for all 3 calls? -
greatwolf over 9 years@Suge he's referring to my 'getfield' usage in my first example. using absolute index rather than relative makes it a bit clearer.
-
Suge about 9 years@greatwolf, thank you very much for your help.Would you help me with another question, if the ignoreColor is also a table such as {imagePath="/var/image.png", fuzzy=0.5, ignoreColor={0xffffff, 0x2d2d2d, 0x0000ff}}, the fuzzy and ignoreColor are optional, and the element number of ignoreColor is unsure. How can I get the values in ignoreColor?Thanks for all your help:)
-
greatwolf about 9 years@Surge I'm not sure what you mean by element number. Are you asking how to provide a default table if the
ignoreColor
table isn't given? -
Suge about 9 years@greatwolf, thank you for reply. I mean in this table {imagePath="/var/image.png", fuzzy=0.5, ignoreColor={0xffffff, 0x2d2d2d, 0x0000ff}}, the value of ignoreColor is an array(table), but the member count of ignoreColor is unsure. Meanwhile the fuzzy and ignoreColor are optional.I mean, if ignoreColor is given, it's value is an array(table).At this sense, how to get all the values inside {imagePath="/var/image.png", fuzzy=0.5, ignoreColor={0xffffff, 0x2d2d2d, 0x0000ff}}?
-
greatwolf about 9 years@Suge To get the values out of
ignoreColor
you unpack it to the stack similar to the outer table. You can uselua_rawgeti
on 'ignoreColor' table. To get the element count of 'ignoreColor' uselua_objlen
. -
greatwolf about 9 years@Suge you might find this helpful as a reference.
-
Suge about 9 years@greatwolf, thank you so much, would have a look at my code here: stackoverflow.com/questions/18637314/…
-
greatwolf about 9 yearsIs there still something else you need addressed? If not you should accept this as an answer if it solves your problem satisfactory.