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+,可以很方便地加入嵌入式程序中。
  • 可擴展:Lua 提供非常易于使用的擴展接口和機制。由宿主語言(通常是 C、C++)提供功能,Lua 如同內(nèi)置功能一樣進(jìn)行調(diào)用。
  • 支持面向過程編程和函數(shù)式編程
  • 自動內(nèi)存管理。只提供一種通用類型的表(table),可以用來實現(xiàn)數(shù)組,哈希表,集合,對象等。
  • 提供多線程(協(xié)同進(jìn)程)支持

但 Lua 目前沒有提供強大的庫,不適合作為開發(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 語言交互是其最大的魅力之一。

運用 C 的庫擴展了其強大的功能。

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

  • 讀寫 Lua 全局變量的函數(shù)
  • 調(diào)用 Lua 函數(shù)的函數(shù)
  • 運行 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 (直接運行 Lua 代碼)或 luaL_dofile (直接運行 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 文件的機制。

如果需要訪問 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)機 如果內(nèi)存不足返回 NULL
lua_State *lua_newstate (lua_Alloc f, void *ud); 獲取一個新的 Lua 狀態(tài)機
lua_State* lua_open(); 獲取一個新的 Lua 狀態(tài)機 參數(shù) f 指定內(nèi)存分配函數(shù),參數(shù) ud 是傳給 f 函數(shù)的指針。如果內(nèi)存不足返回 NULL
void lua_close(lua_State *L); 銷毀 Lua 狀態(tài)機所有對象,回收分配的內(nèi)存
void luaL_openlibs(lua_State *L); 在給定的 Lua 狀態(tài)機中打開所有的標(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)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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

友情鏈接更多精彩內(nèi)容