在开发 C/C++ 与 Lua 交互程序的过程中,Lua_gettable() 经常会使用,函数声明在 lua.h 里,其实现是在 liblua.a 库里。该函数原型为:
int lua_gettable (lua_State *L, int index);
Pushes onto the stack the value t[k]
, where t
is the value at the given index and k
is the value at the top of the stack.
This function pops the key from the stack, pushing the resulting value in its place. As in Lua, this function may trigger a metamethod for the "index" event (see §2.4).
Returns the type of the pushed value.
参数:
L: 一般是通过 luaL_newstate() 获取
index: 这个并不好理解,这个index所指向的值,就是你想要获取的对象。
翻译成中文就是:把t[k] 的值压入栈,这里的t指有效索引index指向的值,而k则是栈顶放的值。这个函数会弹出栈上的key,把结果放在栈上相同的位置,即把table[key]对应的值放到栈顶。
光靠文字其实是不好理解的,需要结合代码来理解,但在此之前开发人员必须时刻在脑子里有一个栈的数据结构,以及每个对象在栈中的位置。如果栈中对象的位置搞错,则很多带有 index 参数的函数可能都取不到正确的结果。
有 init.lua 脚本如下:
--定义了一个全局表
COM = {}
--定义了一个局部函数
local function add(a, b)
print("a = "..a);
print("b = "..b);
return a + b;
end
COM =
{
width = 2550,
myAdd = add,
}
ATMCtrl = {
channalNum = 8,
title = "ATM machine"
}
Global = {
AtmCtrl = ATMCtrl
}
定义了一个 table 名为 Global,为全局变量。此 table 内容里有一个对象名为 AtmCtrl,此对象也是一个 table,此 table 里有两个元素。下面我要取到 ATMCtrl 里的元素 title 的值,该怎么获取呢?看如下代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#include <lauxlib.h>
#include <lua.h>
#include <lualib.h>
}
#endif
int main()
{
lua_State *L = luaL_newstate();
luaL_openlibs(L);
if(luaL_loadfile(L, "init.lua"))
{
printf("load file: hello.lua faild...\n");
lua_close(L);
return 1;
}
lua_pcall(L, 0, 0, 0); /* 前面这几步都基本固定 */
lua_getglobal(L, "Global"); /* 先找到表 */
if(lua_type(L, -1) != LUA_TTABLE)
{
printf("can not find table: Global \n");
lua_close(L);
return 1;
}
lua_pushstring(L, "AtmCtrl"); /* 将要找的关键字入栈 */
int type = lua_gettable(L, -2); /* 如果找到则将 AtmCtrl 的值入栈,即放到栈顶 */
if(lua_type(L, -1) != LUA_TTABLE) /* 栈顶是否是要找到类型 */
{
printf("AtmCtrl is not a table\n");
lua_close(L);
return 1;
}
lua_pushstring(L, "title");
type = lua_gettable(L, -2);
printf("get type: %d\n", type);
if(LUA_TSTRING == lua_type(L, -1))
{
char buf[32] = {0};
size_t len = sizeof(buf);
memcpy(buf, lua_tolstring(L, -1, &len), sizeof(buf));
printf("get title: %s\n", buf);
}
lua_close(L);
return 0;
}
主要通过 5 步就可以获取到 title 的值:
1, lua_getglobal(L, "Global")
通过这个函数,找到名为 Global 的全局 table,如果找到则将Global 的值 压入栈顶,就是一个 table,所以我们可以通过 lua_type(L, -1) 判断栈顶对象的类型。
if(lua_type(L, -1) != LUA_TTABLE)
{
printf("can not find table: Global \n");
lua_close(L);
return 1;
}
2,lua_pushstring(L, "AtmCtrl")
将要找到对象的名称压入栈顶,记住,此时字符串 "AtmCtrl" 在栈顶位置,而第一步中的 Global 值已经在 "AtmCtrl" 的下面,即 "AtmCtrl" 的 index 为 -1, Global 的值的 index 为 -2。
3,lua_gettable(L, -2)
看我们上面的翻译:把 t[k] 的值压入栈,这里的 t 指有效索引 index 指向的值,而 k 则是栈顶放的值。很明白了,其实就是把 index = -2 位置的 Global["AtmCtrl"] 的值放到原来 k 的位置(栈顶),即 k 被弹出了,如果能找到 Gloabl["AtmCtrl"],则取到的值就在栈顶了。因为 AtmCtrl 也是一个 table,所以我们还是可以这样判断:
if(lua_type(L, -1) != LUA_TTABLE) /* 栈顶是否是要找到类型 */
{
printf("AtmCtrl is not a table\n");
lua_close(L);
return 1;
4,lua_pushstring(L, "title")
5,lua_gettable(L, -2)
后面两步就是重复第 2,3 步了。最终 title 的值被放到了栈顶,所以最后我们要把栈顶的元素取出来:
if(LUA_TSTRING == lua_type(L, -1))
{
char buf[32] = {0};
size_t len = sizeof(buf);
memcpy(buf, lua_tolstring(L, -1, &len), sizeof(buf));
printf("get title: %s\n", buf);
}
总结:lua_gettable() 使用的要点是时刻在脑子里有栈的数据结构,同时要记住栈中元素的位置以及类型,这样不管元素是什么类型,才能压入正确的 key,并取得正确的 t[k] 的值。