lua C api
PS:這里是默認(rèn)我已經(jīng)學(xué)完了lua腳本的基本知識(包括table氨淌,元表,函數(shù)村视,基本庫官套, 文件io,庫導(dǎo)入等等)
lua是c寫的蚁孔,無論是lua調(diào)用c還是c調(diào)用lua都非常容易奶赔,以下是基于文檔做的一些學(xué)習(xí)筆記,在文檔的索引可以快速找到api的名稱方便參考杠氢,文檔地址如下:
官網(wǎng)5.3文檔:http://www.lua.org/manual/5.3/#index
中文文檔:http://www.runoob.com/manual/lua53doc/contents.html#index
文檔包括兩部分站刑,一部分是介紹lua的語法,以及一些注(keng)意(die)事項,比如其中說到空字符串和0都被認(rèn)為是true鼻百,恩绞旅,要注意(MDZZ),感覺lua的強(qiáng)大之處在于他的table(手動咸魚)温艇,下面開始修仙因悲,下面通過問答的方式給自己學(xué)習(xí)lua做一些筆記,在此之前勺爱,先編譯lua晃琳,我們到官網(wǎng)可以下載lua的源碼
源碼下載頁面:http://www.lua.org/download.html
5.3源碼下載:http://www.lua.org/ftp/lua-5.3.4.tar.gz
lua源碼非常小,很容易編譯,windows下卫旱,裝個Mingw即可用make編譯人灼,以下是linux的
1.下載解壓源碼
wget http://www.lua.org/ftp/lua-5.3.4.tar.gz
tar -xzvf lua-5.3.4.tar.gz
~/local/lua/lua-5.3.4$ make
Please do 'make PLATFORM' where PLATFORM is one of these:
aix bsd c89 freebsd generic linux macosx mingw posix solaris
See doc/readme.html for complete instructions.
上面提示指定編譯選項,如果是windows下用Mingw的顾翼,就make -j12 mingw
, -j12是多線程編譯投放,分12個線程編譯,現(xiàn)在是debian暴构,可以選擇posix跪呈,如果提示缺少一些庫段磨,使用apt-get 安裝即可
make -j12 posix
編譯成功后取逾,在src文件生成一個lua(lua解釋器),luac(lua腳本編譯器),以及靜態(tài)庫liblua.a,c調(diào)用lua的時候苹支,現(xiàn)在是用靜態(tài)庫砾隅,現(xiàn)在把以下文件復(fù)制到項目目錄下
頭文件:lua.h lualib.h lauxlib.h luaconf.h
靜態(tài)庫文件:liblua.a
我的項目目錄為:~/project/lua
我把頭文件放置在~/project/lua/include
靜態(tài)庫文件放在~/project/lua/lib
以下所有的操作都是在項目目錄(用$PRO_HOME描述這個目錄)
1.c是如何調(diào)用lua寫的代碼的?
1.首先了解债蜜,lua在c代碼中是如何“工作”的晴埂,在c中要調(diào)用lua,首先我得創(chuàng)建一個lua狀態(tài)機(jī)(lua_State)
文件$PRO_HOME/main.c
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
int main(void)
{
//創(chuàng)建一個lua狀態(tài)機(jī)
lua_State *L = luaL_newstate();
//銷毀這貨
lua_close(L);
return 0;
}
然后嘗試編譯這個源文件
$gcc -I ../include -c main.c
$gcc -lm -o main main.o ../lib/liblua.a
編譯成功說明配置沒有問題
c調(diào)用lua代碼寻定,首先要學(xué)會怎么把lua代碼“翻譯”成c的代碼儒洛,先不著急如何把lua代碼加載到lua狀態(tài)機(jī)運(yùn)行,先了解下它是怎么運(yùn)行的狼速,根據(jù)文檔參考琅锻,寫以下一段代碼
-- a是一個全局變量
a="測試"
print(a)
a是一個全局變量,在lua中向胡,無非在維護(hù)一個堆棧stack和一個環(huán)境表_G(暫時理解)
那么用c怎么寫呢恼蓬?
1.創(chuàng)建一個狀態(tài)機(jī)(lua_State),加載基本庫(luaL_openlibs())
2.把字符串“測試”壓入堆棧(lua_pushstring)
3.把這個字符串彈出僵芹,設(shè)置為global处硬,名稱為a(lua_setglobal())
4.從全局變量中,把print函數(shù)壓棧(lua_getglobal())
5.把參數(shù)a從全局變量中壓棧(lua_getglobal())
6.調(diào)用lua_call執(zhí)行函數(shù)
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
int main(void)
{
lua_State *L = luaL_newstate();
//加載基本庫(print在其中)
luaL_openlibs(L);
//這里相當(dāng)于設(shè)置全局變量a="測試"
lua_pushstring(L,"測試");
lua_setglobal(L,"a");
//print函數(shù)壓棧
lua_getglobal(L,"print");
//參數(shù)壓棧yiban
lua_getglobal(L,"a");
//調(diào)用函數(shù),1個參數(shù)拇派,0個返回值
lua_call(L,1,0);
lua_close(L);
return 0;
}
小總結(jié):
在lua 的 C api中荷辕,
數(shù)據(jù)類型有:
lua_Integer 整形
lua_Number 默認(rèn)對應(yīng)的是C double
lua_Unsigned 無符號整形
字符串、布爾型或者是lua的table之類的件豌,都是不能直接“拿出來”的
如果要操作桐腌,設(shè)置某某某的變量,可以通過lua_pushxxxx來把對應(yīng)的數(shù)據(jù)類型的變量的值壓入堆棧苟径,如果案站,要把變量設(shè)置為一個全局變量,就把它設(shè)置為global(lua_setglobal()),lua_setglobal會把棧頂?shù)脑貜棾鲶⊙危≡O(shè)置到環(huán)境表承边,詳情查看文檔,
關(guān)于堆棧
lua的堆棧是lua自己實(shí)現(xiàn)的一個數(shù)據(jù)結(jié)構(gòu)石挂,并不是c語言執(zhí)行時的那個堆棧博助,這個堆棧,由棧底往棧頂數(shù)痹愚,元素的序號是1 2 3 4 5...富岳,這是它的絕對索引的方式,還有它支持負(fù)索引拯腮,也就是參考點(diǎn)是棧頂窖式,而不是棧底,比如-1代表的是棧頂?shù)脑兀?2代表棧頂?shù)南乱粋€元素
對于堆棧的操作
有:
1.獲取棧頂?shù)乃饕?lua_gettop(L)(這個值动壤,可以當(dāng)做是棧元素個數(shù))
2.把數(shù)據(jù)壓棧(lua_pushxxx萝喘,根據(jù)壓入的數(shù)據(jù)類型不一樣,有對應(yīng)有一系列的操作函數(shù),例如琼懊,lua_pushstring(L,"測試"),把字符串壓入阁簸,詳情看文檔lua_pushxxxx),又或者是
3.把堆棧的元素“讀取”出來哼丈,lua_toxxxx,就可以不彈出堆棧中的數(shù)據(jù)启妹,把它轉(zhuǎn)換成c的數(shù)據(jù)類型,例如:lua_tolstring,注意醉旦,這個返回值是const類型饶米,也就是說你不能對他進(jìn)行更改,如果要做其他用途髓抑,你需要
把他copy出來
4.更改元素在堆棧中的位置
5.lua有垃圾回收機(jī)制GC咙崎,一般不用擔(dān)心內(nèi)存釋放的問題
2.如何在lua狀態(tài)機(jī)中執(zhí)行一個c寫的函數(shù)?
剛剛已經(jīng)學(xué)了吨拍,如何在c中褪猛,“執(zhí)行”lua,這個print函數(shù)他已經(jīng)實(shí)現(xiàn)了羹饰,但是我們自己怎么實(shí)現(xiàn)一個函數(shù)伊滋,然后在lua中調(diào)用呢?
這個函數(shù)可以是
1.lua寫的函數(shù)
2.c寫的可以讓lua識別的函數(shù)
我們先來搞第二種,程序還是在原來的基礎(chǔ)上進(jìn)行擴(kuò)充
我們把print換成我們自己實(shí)現(xiàn)的一個函數(shù)队秩,這個函數(shù)在lua里叫print2,它比較簡單笑旺,只能接受一個參數(shù)掂恕,不做任何檢查该押,也不做任何的錯誤的處理
lua注冊的函數(shù)的類型是:
static int fun(lua_State *L);
返回值是這個函數(shù)的返回值個數(shù)(因為lua支持多個返回值,執(zhí)行完畢后骑篙,把返回值依次壓棧,然后返回返回值個數(shù)就行了)乌妙,調(diào)用結(jié)束后使兔,堆棧中剩下的是fun的返回值(如果有返回值,并且按照順序壓棧)
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
static int print2(lua_State *L)
{
const char * s = luaL_optlstring (L,1,"啥都沒",NULL); //獲取函數(shù)調(diào)用時第1個參數(shù)為字符串藤韵,如果參數(shù)不存在或者是nil就返回“啥都沒”虐沥,并且把長度放在第四個參數(shù)(這里設(shè)置為NULL,不獲取長度),
printf("這是:%s\n",s);
return 0; //返回值個數(shù)為0
}
int main(void)
{
lua_State *L = luaL_newstate();
luaL_openlibs(L); //加載基本庫(print在其中)
//這里相當(dāng)于設(shè)置全局變量a=image.png"測試"
lua_pushstring(L,"測試");
lua_setglobal(L,"a");
//注冊這個函數(shù)到全局表
lua_register(L,"print2",print2);
lua_getglobal(L,"print2"); //把這個函數(shù)從全局表中壓棧
lua_getglobal(L,"a"); //參數(shù)壓棧
lua_call(L,1,0); //調(diào)用函數(shù),1個參數(shù)泽艘,0個返回值
lua_close(L); //關(guān)閉狀態(tài)機(jī)
return 0;
}