Lua —— 輕量小巧腳本語言澳淑,支持與C相互調(diào)用

Lua —— 輕量小巧腳本語言,支持與C相互調(diào)用

Lua 語言 logo

Lua 是巴西里約熱內(nèi)盧天主教大學(xué)(Pontifical Catholic University of Rio de Janeiro)里的一個研究小組于 1993 年開發(fā)宪巨。

Lua 用標(biāo)準(zhǔn) C 語言編寫并開放源代碼轴术。

優(yōu)勢:

  • 輕量級:使用標(biāo)準(zhǔn)C語言編寫,編譯后僅僅100k+巫玻,可以很方便地加入嵌入式程序中丛忆。
  • 可擴(kuò)展:Lua 提供非常易于使用的擴(kuò)展接口和機(jī)制。由宿主語言(通常是 C仍秤、C++)提供功能熄诡,Lua 如同內(nèi)置功能一樣進(jìn)行調(diào)用。
  • 支持面向過程編程和函數(shù)式編程
  • 自動內(nèi)存管理诗力。只提供一種通用類型的表(table)凰浮,可以用來實現(xiàn)數(shù)組,哈希表苇本,集合袜茧,對象等。
  • 提供多線程(協(xié)同進(jìn)程)支持

但 Lua 目前沒有提供強(qiáng)大的庫瓣窄,不適合作為開發(fā)獨立應(yīng)用程序的語言使用惫周。

Lua 數(shù)據(jù)類型

數(shù)據(jù)類型 說明
nil 表示一個無效的值(類似于null、NULL康栈、false等)
boolean 布爾型,true 或 false
number 雙精度類型的實浮點數(shù)
string 字符串有一對雙引號("")或單引號('')表示
function 由 C 或 Lua 編寫的函數(shù)
userdata 表示任意存儲在變量中的 C 數(shù)據(jù)結(jié)構(gòu)
thread 表示執(zhí)行獨立的線路喷橙,用于執(zhí)行協(xié)同程序
table Lua 中的表(table)其實是一個 "關(guān)聯(lián)數(shù)組"(associative arrays)啥么,數(shù)組的索引可以是數(shù)字或者是字符串。在 Lua 里贰逾,table 的創(chuàng)建是通過 "構(gòu)造表達(dá)式" 來完成悬荣,最簡單構(gòu)造表達(dá)式是 {},用來創(chuàng)建一個空表疙剑。

測試數(shù)據(jù)類型(使用 type ):


print(type("Hello world"))      --> string
print(type(10.4*3))             --> number
print(type(2))                  --> number
print(type(3.14))               --> number
print(type(print))              --> function
print(type(type))               --> function
print(type(true))               --> boolean
print(type(nil))                --> nil
print(type(type(nil)))          --> string

Lua 與 C 語言的交互

Lua 能與 C 語言交互是其最大的魅力之一氯迂。

運(yùn)用 C 的庫擴(kuò)展了其強(qiáng)大的功能践叠。

C 與 Lua 交互的部分稱為 C API。C API 是一個 C 代碼與 Lua 進(jìn)行交互的函數(shù)集嚼蚀。主要組成部分為:

  • 讀寫 Lua 全局變量的函數(shù)
  • 調(diào)用 Lua 函數(shù)的函數(shù)
  • 運(yùn)行 Lua 代碼片段的函數(shù)
  • 注冊 C 函數(shù)然后可以在 Lua 中被調(diào)用的函數(shù)

C 與 Lua 之間采用一個虛擬的棧進(jìn)行通信禁灼,這樣巧妙地解決了數(shù)據(jù)類型匹配問題和內(nèi)存管理不一致的問題。

所有 C 與 Lua 之間的數(shù)據(jù)交換也都通過這個棧來完成轿曙。

Lua 以一個嚴(yán)格的 LIFO (后進(jìn)先出)規(guī)則來操作棧弄捕。

1. C 調(diào)用 Lua

初始化和結(jié)束接口。


lua_State *L = lua_open();    // 創(chuàng)建 lua_State 堆棧(用于交換數(shù)據(jù))导帝。
luaL_openlibs(L);             // 初始化堆棧

...

lua_close(L);                 // 釋放

C 與 Lua 的交互方式可以是通過 luaL_dostring (直接運(yùn)行 Lua 代碼)或 luaL_dofile (直接運(yùn)行 Lua 文件)守谓。

如 Lua 文件


// 文件名: test_lua.lua
print("This is Lua !")

可以執(zhí)行:


// 可以直接執(zhí)行代碼
const char * buf = "print("This is Lua !")";
luaL_dostring(L, buf);

// 也可以直接執(zhí)行文件
luaL_dofile(L, "test_lua.lua");

由于沒有 include Lua 文件的機(jī)制。

如果需要訪問 Lua 文件內(nèi)的數(shù)據(jù)或接口您单,需要調(diào)用 luaL_loadfile 加載 Lua 文件斋荞,后續(xù)才能進(jìn)行讀取接口或數(shù)據(jù)。

下面以讀取 test_lua.lua 文件為例:


int main()
{
    lua_State *L = lua_open();        // 創(chuàng)建 lua_State 堆棧(用于交換數(shù)據(jù))虐秦。
    luaL_openlibs(L);                 // 初始化堆棧

    if(luaL_loadfile(L, filename))    // 返回 1 則加載出錯
    {
        return -1;
    }
    
    ...

    lua_close(L);                     // 釋放
    return 0;
}

調(diào)用 Lua 函數(shù)的方法

Lua 代碼:


function add(a, b, c)
    local sum=a+b
    return sum,c
end

C 調(diào)用 Lua 函數(shù):


lua_getglobal(L, "add");                      // 在Lua中平酿,函數(shù)等同于變量,所以你可以這樣來取得這個函數(shù)
lua_pushnumber(L, 100);                       // 將參數(shù)壓棧羡疗,對應(yīng) a
lua_pushnumber(L, 20);                        // 將參數(shù)壓棧染服,對應(yīng) b
lua_pushstring(L, "test add function");       // 將參數(shù)壓棧,對應(yīng) c

lua_pcall(L, 3, 2, 0);                        // 調(diào)用函數(shù)叨恨,3個參數(shù)柳刮,2個返回值,錯誤處理函數(shù)(0表示沒有痒钝,其它表示處理函數(shù)在棧的索引)秉颗。

const char * result1 = lua_tostring(L, -1);   // 返回值,對應(yīng)返回的 c (按返回值入棧順序送矩,先是 sum, 后是 c, 所以 c 的順序為 -1)
int result2 = lua_tonumber(L, -2);            // 返回值蚕甥,對應(yīng)返回的 sum

2. Lua 調(diào)用 C

C 函數(shù):


int lua_strlen(lua_State *L)                    // Lua 用棧進(jìn)行數(shù)據(jù)傳遞,所以參數(shù)用棧就可以了
{
    const char * ptr = lua_tostring(L, -1);     // 獲取輸入的第一個參數(shù)
    int len = strlen(ptr);                      // 計算字符串長度
    lua_pushnumber(L, len);                     // 計算結(jié)果入棧
    return 1;
}

int main()
{
    lua_State *L = lua_open();
    luaL_openlibs(L);

    ...

    lua_register(L, "lua_strlen", lua_strlen);  // 需要注冊一下栋荸,聲明暴露給 Lua 調(diào)用的接口和名稱菇怀。

    ...

    lua_close(L);
    return 0;
}

Lua 調(diào)用文件:


function calc_length(s)
    local len=lua_strlen(s)
    return len
end

附錄:C API 一些接口說明

接口 說明 部分參數(shù)說明
lua_State* lua_open(); 獲取一個新的 Lua 狀態(tài)機(jī) 如果內(nèi)存不足返回 NULL
lua_State *lua_newstate (lua_Alloc f, void *ud); 獲取一個新的 Lua 狀態(tài)機(jī)
lua_State* lua_open(); 獲取一個新的 Lua 狀態(tài)機(jī) 參數(shù) f 指定內(nèi)存分配函數(shù),參數(shù) ud 是傳給 f 函數(shù)的指針晌块。如果內(nèi)存不足返回 NULL
void lua_close(lua_State *L); 銷毀 Lua 狀態(tài)機(jī)所有對象爱沟,回收分配的內(nèi)存
void luaL_openlibs(lua_State *L); 在給定的 Lua 狀態(tài)機(jī)中打開所有的標(biāo)準(zhǔn) Lua 庫
int luaL_dofile(lua_State *L, char *lua_script); 加載并執(zhí)行給定的 Lua 文件 成功返回 0,錯誤返回 1
int luaL_dostring (lua_State *L, const char *str); 加載并執(zhí)行給定 string 成功返回 0匆背,錯誤返回 1
int luaL_loadfile (lua_State *L, const char *filename); 從文件加載 chunk 成功返回 0呼伸,錯誤返回 1
int luaL_loadstring (lua_State *L, const char *s); 從字符串加載 chunk 成功返回 0,錯誤返回 1
void lua_pop(lua_State *L, int n); 從棧頂彈出 n 個元素
int lua_gettop (lua_State *L); 返回棧頂元素的索引(也即元素個數(shù))
void lua_call (lua_State *L, int nargs, int nresults); 調(diào)用函數(shù) 參數(shù) nargs 指定函數(shù)參數(shù)個數(shù)钝尸,參數(shù) nresults 指定返回值個數(shù)括享。
int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc); 以保護(hù)模式調(diào)用函數(shù)搂根,如果發(fā)生錯誤,捕捉它铃辖,并將錯誤消息壓入棧剩愧,然后返回錯誤碼。 參數(shù) nargs 指定函數(shù)參數(shù)個數(shù)澳叉,參數(shù) nresults 指定返回值個數(shù)隙咸,參數(shù) errfunc 是錯誤處理函數(shù)在棧的索引(沒有時為 0 )。
int lua_type (lua_State *L, int index); 返回第 index 個數(shù)據(jù)的類型ID 返回類型ID為:LUA_TNIL, LUA_TNUMBER, LUA_TBOOLEAN, LUA_TSTRING, LUA_TTABLE, LUA_TFUNCTION, LUA_TUSERDATA, LUA_TTHREAD, and LUA_TLIGHTUSERDATA
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末成洗,一起剝皮案震驚了整個濱河市五督,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌瓶殃,老刑警劉巖充包,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異遥椿,居然都是意外死亡基矮,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進(jìn)店門冠场,熙熙樓的掌柜王于貴愁眉苦臉地迎上來家浇,“玉大人,你說我怎么就攤上這事碴裙「直” “怎么了?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵舔株,是天一觀的道長莺琳。 經(jīng)常有香客問我,道長载慈,這世上最難降的妖魔是什么惭等? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮办铡,結(jié)果婚禮上辞做,老公的妹妹穿的比我還像新娘。我一直安慰自己寡具,他們只是感情好秤茅,可當(dāng)我...
    茶點故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著晒杈,像睡著了一般。 火紅的嫁衣襯著肌膚如雪孔厉。 梳的紋絲不亂的頭發(fā)上拯钻,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天帖努,我揣著相機(jī)與錄音,去河邊找鬼粪般。 笑死拼余,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的亩歹。 我是一名探鬼主播匙监,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼小作!你這毒婦竟也來了亭姥?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤顾稀,失蹤者是張志新(化名)和其女友劉穎达罗,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體静秆,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡粮揉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了抚笔。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片扶认。...
    茶點故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖殊橙,靈堂內(nèi)的尸體忽然破棺而出辐宾,到底是詐尸還是另有隱情,我是刑警寧澤蛀柴,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布螃概,位于F島的核電站,受9級特大地震影響鸽疾,放射性物質(zhì)發(fā)生泄漏吊洼。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一制肮、第九天 我趴在偏房一處隱蔽的房頂上張望冒窍。 院中可真熱鬧,春花似錦豺鼻、人聲如沸综液。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽谬莹。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間附帽,已是汗流浹背埠戳。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留蕉扮,地道東北人整胃。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像喳钟,于是被迫代替她去往敵國和親屁使。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,077評論 2 355

推薦閱讀更多精彩內(nèi)容

  • Lua 5.1 參考手冊 by Roberto Ierusalimschy, Luiz Henrique de F...
    蘇黎九歌閱讀 13,813評論 0 38
  • 1. 寫在前面 很多時候我們都需要借助一些腳本語言來為我們實現(xiàn)一些動態(tài)的配置奔则,那么就會涉及到如何讓腳本語言跟原生語...
    杰嗒嗒的阿杰閱讀 3,436評論 9 31
  • 第一篇 語言 第0章 序言 Lua僅讓你用少量的代碼解決關(guān)鍵問題蛮寂。 Lua所提供的機(jī)制是C不擅長的:高級語言,動態(tài)...
    testfor閱讀 2,672評論 1 7
  • 名稱 說明 docLua 相關(guān)的文檔应狱,包括了編譯文檔共郭、接口文檔等 Makefile 編譯Lua使用,在...
    一川煙草i蓑衣閱讀 1,451評論 0 1
  • (我想疾呻,你還是可以看看的除嘹,嗯……因為沒有錯別字……因為這是我僅剩的勇氣,臉皮厚成我這樣的也是可以了岸蜗。讓我最后不負(fù)責(zé)...
    于子禾閱讀 205評論 0 0