宿主語言(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) 可以清除指定堆疊上的內容