lua和c模块通信是通过stack来交互数据。lua提供一系列c接口,来实现在c模块中,读取和存储数据到stack。
我们关键是需要了解stack是怎么维护的。才能了解stack维护c接口的含义。lua的stack是一个LIFO结构。lua调用的参数和c模块返回的数据,都是存储在stack上的。
比如有一个call.lua和一个c模块test.c
编译c模块的方法:
cc -c -o test.o test.c -fPIC
cc -o test.so test.o -shared
c模块的代码如下:
#include <lua5.1/lua.h>
#include <lua5.1/lauxlib.h>
static void stackDump (lua_State *L) {
	int i;
	int top = lua_gettop(L); /* depth of the stack */
	printf("top %d\n", top);
	for (i = 1; i <= top; i++) { /* repeat for each level */
		int t = lua_type(L, i);
		switch (t) {
		case LUA_TSTRING:
			printf("%d string: '%s'\n", i, lua_tostring(L, i));
			break;
		case LUA_TBOOLEAN:
			printf("%d bool: %s\n", i, lua_toboolean(L, i) ? "true" : "false");
			break;
		case LUA_TNUMBER:
			printf("%d number: %g\n", i, lua_tonumber(L, i));
			break;
		default:
			printf("%d type: %s\n", i, lua_typename(L, t));
			break;
		}
	}
	printf("\n");
}
static int lua_hello(lua_State *L)
{
	stackDump(L);
	return 0;
}
static const struct luaL_Reg test_apis[] = {
	{"hello", lua_hello},
	{NULL, NULL},
};
int luaopen_test(lua_State *L) {
	luaL_register(L, "test", test_apis);
	return 1;
}call.lua的代码如下
require "test"
data = {}
data["key1"] = "value"
data[2] = 2
errcode, result = test.hello(1, data, 2)调用call.lua
$ ./call.lua
top 3
1 number: 1
2 type: table
3 number: 2
test.hello(1, data, 2) 传入了3个参数。第一个和第三个是整数。第二个是table。
在c模块里面stackDump()打印出stack里面有3个数据,类型也能打出来。
那么问题来了:怎么读取第二个参数table的内容?
方法是把table的内容一个个弹到栈顶,然后读取。
调用lua_next()把table的元素一个个弹出来,就可以了。改造一下stackDump()代码:
static void dump_v(lua_State *L, int i, int level, int newline)
{
	int t = lua_type(L, i);
	if (level)
		printf("%*c", 4 * level, ' ');
	switch (t) {
	case LUA_TSTRING:
		printf("'%s'", lua_tostring(L, i));
		break;
	case LUA_TBOOLEAN:
		printf("%s", lua_toboolean(L, i) ? "true" : "false");
		break;
	case LUA_TNUMBER:
		printf("%g", lua_tonumber(L, i));
		break;
	case LUA_TTABLE:
		printf("%c", newline == 1 ? '{' : '}');
		break;
	default:
		printf("%s", lua_typename(L, t));
		break;
	}
	if (newline)
		printf("\n");
}
static void dump(lua_State *L, int i, int level)
{
	int t = lua_type(L, i);
	dump_v(L, i, level, 1);
	if (t == LUA_TTABLE) {
		lua_pushnil(L);
		while (lua_next(L, i) != 0) {
			dump_v(L, -2, level + 1, 0);
			printf(": ");
			dump(L, -1, 0);
			lua_pop(L, 1);
		}
		dump_v(L, i, level, 2);
	}
}
static void stackDump(lua_State *L) {
	int i;
	int top = lua_gettop(L); /* depth of the stack */
	printf("top %d\n", top);
	for (i = 1; i <= top; i++)
		dump(L, i, 1);
}这样就可以打印出json格式的参数了。
top 3
1
{
'key1': 'value'
2: 2
}
2
stack读取table相关的接口
| int lua_next (lua_State *L, int index); | 将index处的table,弹出一个key value到栈顶。 弹出前,先弹出栈顶一个元素。所以如上述例子所示,通常要先push一个nil。  | 
| int lua_gettable (lua_State *L, int index); | 读取index处table的一个特定key的值。需要先将key push到栈顶。然后调用此函数,会弹出value到栈顶。 | 
| int lua_rawget (lua_State *L, int index); | 和gettable类似,但是是raw get,例如不执行metamethods | 
| int lua_geti (lua_State *L, int index, lua_Integer i); | 和gettable类似。不过key是通过参数i指定,而不是push到栈顶。参数i是整数。这个接口用来读取数组的value很方便。 | 
stack写入table也是类似的。
void lua_newtable (lua_State *L);
先创建一个空的table,然后push到stack上。
将key value push到栈上。然后调用下面这个:
void lua_settable (lua_State *L, int index);
将key/value,加到index指定的table里。加入之后,会把key value pop出来。
void lua_rawset (lua_State *L, int index);
和settable类似,不过不执行metamethods。
例子:
static int lua_hello(lua_State *L)
{
	stackDump(L);
	lua_pushinteger(L, 1234);
	lua_newtable(L);
	lua_pushstring(L, "return_key");
	lua_pushstring(L, "return_value");
	lua_rawset(L, -3);
	return 2;
}push第一个返回值1234。
第二个返回值是一个table。它push一个key value,然后将该key value给这个table。
lua_rawset(L, -3),-3是应为table是stack上倒数第3个。倒数第一个是value。倒数第二个是key。
返回2,表示取栈顶的2个元素。
打印:
err 1234
return_key = return_value