本文将介绍如何在C/C++里面操作Lua的数组和字符串类型,同时还会介绍如何在C/C++函数里面存储Lua状态(registry和upvalue),而registry在使用C/C++自定义类型时非常有用,可以方便地为userdata指定metatable。
C/C++操作Lua数组
Lua数组Overview
在Lua里面,数组只不过是key为整数的table而已。比如一个table为array = {12,”Hello”, “World”},它是一个数组,可以用下面的代码来访问它:
print(array[1]) --这里会输出array的第一个元素12。
print(array[3]) --这里会输出array的第三个元素World
</div>
需要注意的一点就是:Lua的数组的下标是从1开始的。如果你使用下面的语句则会输出nil值:
print(array[0]) --输出nil
print(array["1"]) --输出nil(想想和array[1]的区别:一个是integer作为key,一个是字符串做为key)
</div>
通用Table操作方法
之前我们在教程1中介绍了如何传递Table给Lua,以及在教程3中介绍了如何访问Table的数据。因为数组也是Table,所以我们可以用同样的方式来读取数组。
读取数组
假设我们的Lua Table为array = {“Hello”, 1, “World”, 23.2},那么我们可以用下列函数来访问它:
void readLuaArray(lua_State *L)
{
lua_settop(L,0); //这样确保我们的array是放在当前栈的栈顶。
lua_getglobal(L, "array");
//如果前面不调用lua_settop(L,0),那我们必须要使用luaL_len(L,-1)
int n = luaL_len(L, 1); //luaL_len可以获得table的元素个数
for (int i = 1; i <= n; ++i) {
lua_pushnumber(L, i); //往栈里面压入i
lua_gettable(L, -2); //读取table[i],table位于-2的位置。
//lua_rawget(L, -2); //lua_gettable也可以用lua_rawget来替换
cout<<lua_tostring(L, -1)<<endl;
lua_pop(L, 1);
}
}
</div>
最后输出的结果为:
"Hello", 1, "World", 23.2
</div>
修改数组
现在我们如果想要修改这个数组,把每一个数组的元素都变成”hehe[i]”(i = 1-n),我们看看怎么做。
int writeLuaArray(lua_State *L)
{
lua_settop(L, 0);
lua_getglobal(L, "array");
//确保第一个函数一个要是一个table
luaL_checktype(L, 1, LUA_TTABLE);
int n = luaL_len(L,1);
for (int i = 1; i <= n; ++i) {
lua_pushnumber(L, i);
char buf[256];
sprintf(buf, "hehe%d", i);
lua_pushstring(L, buf);
// lua_settable(L, -3);
lua_rawset(L, -3);
}
return 0;
}
}
</div>
注意这里的lua_rawset和lua_settable是等价的,只不过lua_rawset速度更快。 最后,我们在加载完Lua脚本以后调用这两个函数:
writeLuaArray(L);
readLuaArray(L);
</div>
输出结果为:
readLuaArray: hehe1
readLuaArray: hehe2
readLuaArray: hehe3
readLuaArray: hehe4
</div>
专门的数组操作方法
因为数组一般在程序语言里面都会被特殊对待,Lua也不例外,它的C API还提供另外一种更方便高效地方法来存取数组的元素。
void lua_rawgeti (lua_State *L, int index, int key);
void lua_rawseti (lua_State *L, int index, int key);
</div>
这两个函数后面两个参数的意思分别是:index(table在栈中的索引),key(table中数组的索引,下标从1开始) 接下来,我会通过改造上面的示例来演示这两个API的用法。
读取数组
因为lua_rawgeti(L,t,key)等价于:
lua_pushnumber(L, key);
lua_rawget(L, t);
</div>
因此,我们的读取代码可以改写成下面这样:
void readLuaArray(lua_State *L)
{
lua_getglobal(L, "array");
int n = luaL_len(L, -1);
for (int i = 1; i <= n; ++i) {
lua_rawgeti(L, 1, i);
cout<<"readLuaArray: "<<lua_tostring(L, -1)<<endl;
lua_pop(L, 1);
}
}
</div>
修改数组
同理,lua_rawset(L,t,key)等价于
lua_pushnumber(L,key); //此时的栈 table->value->key
lua_insert(L,-2); //调用完后的栈: table->key->value (table[key]=value)
lua_rawset(L,t);
</div>
相应的修改数组的代码可以修改为:
int writeLuaArray(lua_State

