Lua stacks in C
Jun 6, 2016 · 4 minute readLuaC
Retrospective
In this post we looked a little bit at how Lua uses stacks for a lot of things internally. Now we can look at how we need to explicitely work with the stacks in C when implementing a Lua interface.
The almighty Lua state
When combining C code with Lua there’s exactly one essential piece of information passed from call to call: The Lua state. It is once created and then updated to reflect the current state, you probbaly guessed it: it’s a stack; there’re ways to split the state and of course one can have several states at the same time but in essence there’s supposed to be exactly one and a linear usage.
Doing Lua the hard way: in C
No matter whether you’re implementing functions in C supposed to be called from Lua or calling Lua functions from C, the principle is always the same:
- The function is put on the stack
- The arguments are put on the stack
- The function is called
- The arguments are pulled from the stack
- The function does some processing
- The result is put on the stack
- The functions returns
- The processing continues one step after the function was put on the stack
The calling signature always looks the same:
int func (lua_State *L)
{
}
The lua_State
contains the stack mentioned above, (when called from Lua)
adjusted to only have the passed arguments available on the stack. Now we come
back to the basic three operations which can be applied to the stack:
- push
- pop
- peek
It is good practise to balance the stack (in case you want to call other functions yourself so there’s always the expected number of elements on the stack). This means you should remove any temporary values you created in the function itself.
Then you do the processing and put the result on the stack and return the function with the number of result parameters on the stack.
Let’s have an example:
int minus (lua_State *L)
{
int a = luaL_checknumber (L, 1);
int b = luaL_checknumber (L, 2);
int c = a - b;
lua_pushnumber (L, c);
return 1;
}
So int a = luaL_checknumber (L, 1);
checks whether parameter 1 (from the
bottom of the stack) can be expressed as an integer value and assigns it to the
local variable a or it will create and error and return from the function if
there was no argument or it evaluates to an incompatible type.
int b = luaL_checknumber (L, 2);
does the same with parameter 2 and assigns
it to the local variable b.
luaL_checknumber is a peek operation and will not modify the stack.
Note: Any excess parameter will simply be ignored.
int c = a - b;
computes the result of a - b
and stores it in c.
lua_pushnumber (L, c);
takes the result and creates a new value of type
number with it on the stack.
return 1;
tells the Lua interpreter that there’s one result value to be
kept by the stack; any additional values will automatically be removed but only
if it is called via the Lua interpreter, otherwise (e.g. if functions call one
another) the values will prevail.
Now we’ve seen peek and push operations in action, pop operations are usually used in conjuction with operations which pop values on the stack that need to be gotten rid off. An example would be you creating a new array which is supposed to be returned but then some error occurs so you want to get rid of the array (for symmetry reasons). Or you might be processing an array which will requires to have an index on the stack but will actually put the index and the value on the stack, so the latter will need to be popped of for the next iteration.
In closing
Today we’ve seen how to write a Luaish C function which could be called from Lua or another Luaish C function and the basic stack handling in C. The next posts will contain specific recipes for C lua bindings I had to figure out the hard way.
Until then, take care.