1. 程式人生 > >宿主語言(c++)呼叫Lua原理(lua的堆疊)

宿主語言(c++)呼叫Lua原理(lua的堆疊)

本文主要介紹宿主語言是如何一步步呼叫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) 可以清除指定堆疊上的內容