How to work with tables passed as an argument to lua C function?

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

This function should get the lua table as an argument, so I have to read the fields in the table. I am trying to do as shown below, but my function crashes on startup. Can someone help me 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 to 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}} }
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}} } 
+4
source share
1 answer

When working with the Lua C API, it is important to establish convenient work with the virtual stack - all important language boundary interactions occur there. If you look at the code snippet, it doesn’t look like you are correctly translating the data into C.

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

  • Convert lua input to something you can work with in C.
  • Do the processing or something else that the function should perform.
  • Converts and returns the result if it returns to lua.

As an example, here is 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 store imagePath on the stack since we are holding const char * . Turning this line off will invalidate *imagePath , since lua can compile it.

Alternatively, you can copy the string returned by luaL_checkstring to another buffer. Turning off the string in this case is performed, since we no longer point to the internal buffer belonging to lua.

Edit: If some of the keys in the table are optional, you can use the luaL_opt* functions and provide default values. 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 meaningless value for the key, it will still throw an error. OTOH, if it is absent, then the value is nil and is used by default.

+12
source

Source: https://habr.com/ru/post/1499278/


All Articles