宿主语言(c++)调用Lua原理(lua的堆栈)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhaixh_89/article/details/84798200

本文主要介绍宿主语言是如何一步步调用lua的,这里选取c++作为宿主语言,以前使用cocos调用lua的时候只知道是通过lua虚拟机中的栈来实现的一直没有深入理解,借着这次重新使用的机会,深入理解并作出总结,做一记录(记性不好,可以常回来看看巩固下)先来理一理lua虚拟机的栈:

我画了一张表说明下,此时lua栈里有9个元素,lua的虚拟机堆栈可以向上索引,也可以向下索引,一般使用向下索引多一些
正数索引:栈底是1,然后一直到栈顶依次+1,此时栈顶是9
负数索引:栈顶是-1.然后一直到栈底依次-1,此时栈底是-9

为什么会有两种索引方式呢?仔细观察上图不难看出其好处:其实就是为了方便的获取到栈顶和栈底元素
正数索引:我们不需要知道栈的大小,能轻易获取到栈底索引1
负数索引:同样不需要知道栈的大小,能轻易的获取到栈顶索引-1

下面我们通过代码了解下

Lua代码

function LuaFunc()
    return 1,2,3,4;
end

helloName = {name = "aaa"}
int _tmain(int argc, _TCHAR* argv[])
{
	//①新建虚拟机  
	lua_State *L = luaL_newstate();
	//②载入库  
	luaL_openlibs(L);
 
	//③这里执行 test.lua  Lua文件  
	luaL_dofile(L, "test.lua");
	//④重新设置栈底
	lua_settop(L, 0);
 
	//⑤获取 返回结果  
	lua_getglobal(L, "LuaFunc");

        //判断栈顶的值的类型是否为String, 返回非0值代表成功 */
        int isstr = lua_isstring(L, 1);
        CCLOG("isstr = %d", isstr);
 
	//⑥操作栈调回结果
	lua_pcall(L, 0, 4, 0);
	printf("%s\n", lua_tostring(L, 1));
	printf("%s\n", lua_tostring(L, 2));
	printf("%s\n", lua_tostring(L, 3));
	printf("%s\n", lua_tostring(L, 4));
 
	//⑦一定记得关闭虚拟机  
	lua_close(L);
 
	system("pause");
	return 0;
}

执行输出:
1
2
3
4

分析以上函数:
先是创建lua状态机并加载lua库文件
调用lua_settop(L, 0);重置栈顶的索引值为0,确保后续入栈操作的第一个元素索引为1
调用lua_getglobal(L, "LuaFunc");c++访问虚拟机的栈,将LuaFunc放入栈顶,然后lua虚拟机开始访问栈并取出栈顶元素LuaFunc,
此时栈中元素为nil,lua虚拟机拿到LuaFunc后发送给Lua程序(编译器或者解释器),lua程序会通过lua文件全局表查找LuaFunc,找到"1,2,3,4"
lua程序拿到结果后将其再压入栈,压入顺序为1、2、3、4(从栈底到栈顶)
最后c++调用lua_tostring去栈中读取数据, lua_tostring(L,1)是读取函数读取栈中索引为1的元素,即为字符串1
程序最后关闭lua虚拟机
如果我们要取出上面lua文件中的name字段,该怎么写呢

/* 取得table变量,在栈顶 */
lua_getglobal(L, "helloName");

/* 将C++的字符串放到Lua的栈中,此时,栈顶变为“name”, helloTable对象变为栈底 */
lua_pushstring(L, "name");

/* 
    从table对象寻找“name”对应的值(table对象现在在索引为-2的栈中,也就是当前的栈底),
    取得对应值之后,将值放回栈顶
*/
lua_gettable(L, -2);

/* 现在表的name对应的值已经在栈顶了,直接取出即可 */
const char* sName = lua_tostring(L, -1);
CCLOG("name = %s", sName);

前面创建状态机的步骤我就省略了,基本一样,重点分析下这几个函数
lua_getglobal(L, "helloName");通过lua状态机访问lua程序取得table,此时栈底元素是"helloName", 但是我们要获取的是name字段,因此调用lua_pushstring()函数把C++中的字符串存放到Lua的栈里,此时栈底元素是"helloName",栈顶元素是"name",
然后再调用lua_gettable(L, -2)函数会从栈顶取得栈顶的值,然后根据这个值去索引为-2的table中寻找对应的value值,最后把找到的值放到栈顶。此时栈顶元素为"aaa"
最后我们再lua_tostring(pL, -1)取出值

获取堆栈的值有很多种方法,分别对应不同的变量类型lua_toboolean、lua_toNumber、lua_tocfunction、lua_tostring等

另外使用lua_pop(L,1) 可以清除指定堆栈上的内容

猜你喜欢

转载自blog.csdn.net/zhaixh_89/article/details/84798200