C API
How do I traverse a Lua table?
Traversing a general table uses lua_next. This code is the equivalent of using 'pairs' in Lua:
/* table is in the stack at index 't' */
lua_pushnil(L); /* first key */
while (lua_next(L, t) != 0) {
/* uses 'key' (at index -2) and 'value' (at index -1) */
printf("%s - %s\n",
lua_typename(L, lua_type(L, -2)),
lua_typename(L, lua_type(L, -1)));
/* removes 'value'; keeps 'key' for next iteration */
lua_pop(L, 1);
}
To go over the elements of an array, use lua_rawgeti. This is the fastest form of array access, since no metamethods will be checked.
For example, this function makes a copy of a table passed as its argument:
static int l_copy(lua_State *L) {
// the table is at 1
int i,n = lua_objlen(L,1); // also works for strings, equivalent of #
lua_createtable(L,n,0); // push our new table, with explicit array size
for (i = 1; i<=n; i++) {
lua_rawgeti(L,1,i);
lua_rawseti(L,-2,i); // value is at -1, new table is at -2
}
return 1; // new table remains on stack
}
How would I save a Lua table or a function for later use?
Newcomers are puzzled that there is no lua_totable or lua_tofunction corresponding to lua_tostring, etc. This is because Lua does not expose a general 'Lua object' type; all values are passed using the stack. The registry provides a mechanism for saving references to tables or Lua functions, however.
int ref;
lua_newtable(L); // new table on stack
ref = luaL_ref(L,LUA_REGISTRYINDEX); // pop and return a reference to the table.
Then, when you need to push this table again, you just need to access the registry using this integer reference:
lua_rawgeti(L,LUA_REGISTRYINDEX,ref);
This also works with functions; you use luaL_ref to get a reference to a function which can then be retrieved and called later. This is needed when implementing callbacks; remember to use lua_pcall so that a bad call does not crash your program.
How can I create a multi-dimensional table in C?
See this thread on the Lua mailing list. We have a C matrix V, which is an array of row arrays, and wish to create the Lua equivalent.
int i,j;
lua_createtable(L , nRows, 0); // push the main table T onto the stack
for (j = 1; j <= nRows; j++ ) {
lua_createtable(L , nCols, 0); // push a Row Table R onto the stack
for ( i = 1; i <= nCols; i++ ) {
lua_pushnumber(L, V[j][i]);
// value is at -1, R is at -2
lua_rawseti(L, -2, i); // R[i] = V[j][i]
}
// R is at -1, T is at -2
lua_rawseti(L, -2, j); // T[j] = R
}
Can I use C++ exceptions?
Lua's basic error mechanism uses setjmp, but it is possible to compile Lua so that C++ exceptions can be used.
It is important not to let exceptions propagate across the boundary into Lua, that is, use try..catch with your code, and if an error is caught, then use lua_error to notify Lua itself.
How to bind a C++ class to Lua?
Lunar wraps this common pattern:
#include "lunar.h"
class Account {
lua_Number m_balance;
public:
static const char className[];
static Lunar<Account>::RegType methods[];
Account(lua_State *L) { m_balance = luaL_checknumber(L, 1); }
int deposit (lua_State *L) { m_balance += luaL_checknumber(L, 1); return 0; }
int withdraw(lua_State *L) { m_balance -= luaL_checknumber(L, 1); return 0; }
int balance (lua_State *L) { lua_pushnumber(L, m_balance); return 1; }
~Account() { printf("deleted Account (%p)\n", this); }
};
const char Account::className[] = "Account";
Lunar<Account>::RegType Account::methods[] = {
LUNAR_DECLARE_METHOD(Account, deposit),
LUNAR_DECLARE_METHOD(Account, withdraw),
LUNAR_DECLARE_METHOD(Account, balance),
{0,0}
};
....
Lunar<Account>::Register(L);
This does all the userdata and metatable creation for you; each method of your class iwill be a normal Lua C function that gets its arguments from the stack as usual.
tolua++ is an attractive solution because it can parse 'cleaned' C/C++ headers and generate the bindings.
A very simple example: say we have a burning need for the C function strstr; given this file lib.pkg:
const char *strstr(const char*, const char*);
then tolua -o lib.c lib.pkg will generate a binding file lib.c which can be compiled and linked against the tolua library.
require 'lib' may result in a surprise, since there is no table lib generated, only a global function strstr. To put the function into a tble lib, lib.pkg must look like this:
module lib
{
const char *strstr(const char*, const char*);
}
So .pkg files are not really C/C++ headers; however, it is not difficult to convert headers into .pkg files by cleaning them up.
An alternative to tolua is luabind
SWIG is a popular binding generator which can target Lua as well. If a SWIG binding exists for a library, then it is relatively easy to generate Lua bindings from it.
What's the difference between the lua and the luaL functions?
The lua_* functions form the basic API of Lua. It's the communication channel between the C world and the Lua world. It offers the building blocks that are used by the luaL_* functions from the auxiliary API to offer some higher level functionality and convenience functions.
What am I allowed to do with the Lua stack and its contents in my C functions?
The stack you get in your C function was created especially for that function and you can do with it whatever you want. So feel free to remove function arguments that you don't need anymore. However, there is one scenario to watch out for: never remove a Lua string from the stack while you still have a pointer to the C string inside it (obtained with lua_tostring):
/* assume the stack contains one string argument */
const char* name = lua_tostring(L, 1);
lua_pop(L, 1); /* careful... */
puts(name); /* bad! */
If you remove the Lua string from the stack there's a chance that you removed the last reference to it and the garbage collector will free it at the next opportunity, which leaves you with a dangling pointer.
What is the difference between userdata and light userdata?
lua_newuserdata allocates a block of memory of the given size. The result is called a userdatum, and differs from a block allocated with malloc in two important ways: first, it will be collected by the garbage collector, and second its behaviour can specified by a metatable, just like with Lua tables. There are two metamethods which can only be used with userdata; __len implements the size operator (#) and __gc provides a function which will be called when the userdatum is garbage collected. A good example of this in the standard Lua library are file types, where __gc will close the file handle. The metatable also acts as the unique type of a userdatum.
Light userdata, on the other hand, are simple wrappers around a C pointer. They don't have metatables, and aren't garbage-collected. Their purpose is to generate unique 'handles' which can be cheaply compared for equality.
The implementation of a simple array object is discussed in PiL, starting with a simple set of functions and ending up with an object which can be indexed like a regular Lua table.