Lua和其他宿主語(yǔ)言交互原理剖析
?
題外話:今天周六,剛好有時(shí)間就把我這次項(xiàng)目組內(nèi)部分享的文章貼出來(lái),分享給大家,同時(shí)也方便以后自己翻閱添坊。
一、Lua簡(jiǎn)介
? ??????目標(biāo):Lua語(yǔ)言本身是用C語(yǔ)言來(lái)編寫開發(fā)的箫锤。當(dāng)初設(shè)計(jì)Lua的目標(biāo)就是想讓Lua成為一個(gè)很容易嵌入其它語(yǔ)言中使用的語(yǔ)言”嵬埽現(xiàn)有很多應(yīng)用程序使用Lua作為自己的嵌入式腳本語(yǔ)言,以此來(lái)實(shí)現(xiàn)可配置性谚攒、可擴(kuò)展性阳准。
? ??????特性:Lua是一種輕量語(yǔ)言,它的官方版本只包括一個(gè)精簡(jiǎn)的核心和最基本的庫(kù)馏臭。源碼是開源的野蝇,把源碼編譯之后僅僅一百多K,可以很方便的嵌入別的程序里括儒。Lua同時(shí)也易于擴(kuò)展绕沈,由宿主語(yǔ)言(通常是C或C++)開發(fā)和提供一些功能,Lua可以很容易的使用它們帮寻。
二乍狐、lua和其他宿主語(yǔ)言交互的橋梁-棧
? ??????1、Lua與其他宿主語(yǔ)言的交互固逗,其實(shí)是通過(guò)C語(yǔ)言實(shí)現(xiàn)的虛擬機(jī)棧來(lái)實(shí)現(xiàn)的交互的浅蚪。Lua在C函數(shù)和腳本函數(shù)之間創(chuàng)建了一種虛擬棧的結(jié)構(gòu),棧的元素代表一個(gè)Lua的值(table, string, nil等等8種基本類型)抒蚜。Lua提供了一系列C API用于操作棧掘鄙,比如將元素入棧,出棧嗡髓,刪除等等。在調(diào)用這些API之前收津,通常都需要將必須的值壓入棧饿这,在API調(diào)用結(jié)束后浊伙,再把結(jié)果從棧中取出。
??? ????2长捧、接下來(lái)我們看一下Lua的虛擬機(jī)棧大概是個(gè)什么樣子的嚣鄙。下面是我用mspaint手繪的一張圖:
從這張圖中我們可以看出:
1、棧的特性串结,先進(jìn)后出哑子。
2、棧中的每個(gè)元素可以為任意的lua的8個(gè)基本數(shù)據(jù)類型中的一種肌割。
3卧蜓、假如lua虛擬機(jī)棧中有l(wèi)ua的8個(gè)基本數(shù)據(jù)類型。那么從棧頂?shù)綉?zhàn)底用正數(shù)索引表示就是8到1把敞,棧頂是8弥奸,棧底是1。用負(fù)數(shù)索引表示就是-1到-8奋早,棧頂是-1盛霎,棧底是-8。
4耽装、正數(shù)索引的好處就是愤炸,棧底永遠(yuǎn)是1。
5掉奄、 負(fù)數(shù)索引的好處就是规个,棧頂永遠(yuǎn)是-1。
三挥萌、常用接口函數(shù)講解
下面一張是宿主程序和Lua虛擬機(jī)交互圖绰姻,這張圖大致演示了,宿主語(yǔ)言怎么和Lua語(yǔ)言進(jìn)行交互的引瀑。
1狂芋、luaL_dofile(L, fn)
??? luaL_dofile函數(shù)實(shí)際上是執(zhí)行了lua_load函數(shù)來(lái)加載lua文件,加載成功之后會(huì)編譯一個(gè)代碼塊作為一個(gè)匿名函數(shù)放置在棧頂憨栽。
??? 然后調(diào)用lua_pcall執(zhí)行匿名代碼塊帜矾,最終C代碼才能調(diào)用lua中的函數(shù)和變量等等。
2屑柔、lua_call(lua_State
*L, int nargs, int nresults) 和lua_pcall(lua_State *L,int nargs, int nresults, int errfunc)
??? lua_call在無(wú)保護(hù)模式下面運(yùn)行的屡萤,出錯(cuò)直接拋出異常。而lua_pcall在保護(hù)模式模型下運(yùn)行的掸宛,出錯(cuò)獲捕獲異常信息死陆。這兩個(gè)函數(shù)調(diào)用之后都會(huì)把棧頂?shù)臄?shù)據(jù)彈出棧。
3、lua_getfield(lua_State*L, int idx, const char *k)
??? lua_getfield是用來(lái)取出lua中的一個(gè)值措译,一般都是先找到table所在的位置索引index别凤,然后傳入key,取出值领虹。???
??? 1规哪、lua_getfield(L, LUA_GLOBALSINDEX, key)
??? 等價(jià)于lua_getglobal(L,key)
??? 含義:從全局表中取出key字段的值
?? 2、lua_getfield(L, index, key)
??? 等價(jià)于:lua_pushstring(L,key)??? lua_gettable(L,index)
??? 含義:從棧中找到table所在的位置索引index塌衰,然后取出key字段的值诉稍,并把值壓入棧中。
4最疆、lua_setfield(lua_State*L, int idx, const char *k)
??? lua_setfield用來(lái)改變lua中的一個(gè)值杯巨,一般都要先把改變的vlaue通過(guò)Push壓入棧等(lua_pushstring、lua_pushnumber等)肚菠,然后在調(diào)用lua_setfield來(lái)進(jìn)行取值賦值操作
??? 1舔箭、lua_setfield(L, LUA_GLOBALSINDEX, key)
??? 等價(jià)于:lua_setglobal(L,key)???
??? 含義:從全局表中找到key,然后用棧頂?shù)闹祐alue蚊逢,覆蓋掉key原來(lái)的值层扶。最后把棧頂?shù)闹祻棾鰲!?/p>
?? 2烙荷、lua_setfield(L, index, key)
??? 等價(jià)于:
??? lua_pushstring(L,key);
??? lua_pushnumber(L,value);
??? lua_settable(L,index);
??? 含義:從棧中找到key镜会,然后取出他在table中的位置索引index的值,用棧頂?shù)闹蹈采w掉key原來(lái)的值终抽。最后把棧頂?shù)闹祻棾鰲?/p>
四戳表、示例
這次演示采用的宿主語(yǔ)言是C++。
我們看一下第一個(gè)例子:C++如何調(diào)用Lua的函數(shù)昼伴。
Lua碼如下:
C++代碼如下
運(yùn)行結(jié)果:
帶棧信息的運(yùn)行結(jié)果:
第二個(gè)例子:Lua如何調(diào)用C++中的函數(shù)
Lua代碼如下:
C++代碼如下:
運(yùn)行結(jié)果:
帶棧信息的運(yùn)行結(jié)果:
第三個(gè)例子:C++如何獲得Lua中的變量和Table的值匾旭,同時(shí)修改他們。
Lua代碼如下:
C++代碼如下:
運(yùn)行結(jié)果:
? ??????從這三個(gè)例子里面我們可以看出圃郊,lua和宿主語(yǔ)言的交互主要是通過(guò)棧來(lái)完成的价涝。時(shí)刻要留言棧內(nèi)哪些元素進(jìn)棧了,那些元素出棧了持舆,棧內(nèi)還有哪些元素色瘩。
最后給大家推薦一個(gè)軟件:Word轉(zhuǎn)PDF? https://www.ilovepdf.com/zh-cn/word_to_pdf