快速掌握Lua 5 3 從Lua中呼叫C函式

2021-07-10 15:46:51 字數 3703 閱讀 3850

a:

1、程式主體在c中執行,c函式註冊到lua中。c呼叫lua,lua呼叫c註冊的函式,c得到函式的執行結果。

2、程式主體在lua中執行,c函式作為庫函式供lua使用。

第一種方式看起來很羅嗦,也很奇怪。既然程式主體執行在c中,而且最終使用的也是c中定義的函式,那麼為何要將函式註冊給lua,然後再通過lua呼叫函式呢?

相比於第一種方式,第二種方式使用的更加普遍。

乙個lua庫(lua本身所提供的庫)實際上是乙個定義了若干lua函式的」chunk」,這些函式通常作為」table」的域來儲存。乙個c庫(c語言編寫,註冊給lua使用的庫)的實現方式類似於lua庫的實現方式。首先c庫中定義提供給lua使用的函式,其次還需要乙個「特殊函式」,它的作用是註冊所有c庫中的函式,並將它們儲存在適當的位置(類似於lua庫中的函式作為」table」的域來儲存)。

lua可以呼叫c庫中的函式,就是通過這個註冊的過程實現的。一旦c函式註冊到lua中,lua就可以直接通過c函式的引用獲取到c函式的位址(這也是我們註冊的意義,將c函式的位址提供給lua)。換句話說,一旦c函式註冊,lua呼叫他們不依賴於函式名,」package」位置,或者是可見規則。

以上兩種方式下面都會列舉對應的例子,理解第一種方式,將有助於你理解第二種方式的實現流程。

a:當c呼叫lua函式的時候,必須遵循一些簡單的協議來傳遞引數和獲取返回結果。同樣的,從lua中呼叫c函式,也必須遵循一些協議來傳遞引數和獲得返回結果。此外,從lua呼叫c函式我們必須註冊函式,也就是說,我們必須把c函式的位址以乙個適當的方式傳遞給lua直譯器。

任何在lua中註冊的c函式必須有同樣的原型,

typedef int (*lua_cfunction) (lua_state *l); // 定義在"lua.h"中。

被註冊的c函式接收乙個單一的lua_state型別的引數,同時返回乙個表示返回值個數的數字。函式在將返回值入棧之前無需清理棧,在函式返回之後,lua會自動清除棧中返回結果下面的所有內容。

a:

#include 

#include

#include

#include

#include

#include

#include

static

int l_sin(lua_state *l)

int main(void)

prompt> gcc main.c -llua

-ldl

-lm-wall

prompt>

./a.out

0.99999968293183

另乙個例子(假定我們的系統符合」posix」標準)的功能類似於ls,將指定目錄中的所有檔案以陣列的形式返回。當有錯誤發生時,返回nil加上乙個描述錯誤資訊的字串。

#include 

#include

#include

#include

#include

#include

#include

#include

#include

#include

static

int l_dir(lua_state *l)

/* create result table */

lua_newtable(l);

i = 1;

while((entry = readdir(dir)) != null) // 逐一讀取目錄中的檔案。

closedir(dir);

return

1; // 返回值只有乙個,"table"。

}int main(void)

prompt> gcc main.c -llua

-ldl

-lm-wall

prompt>

./a.out

1 vermilliontear

2 git3.

4..5 lost+found

a:我們使用上面的第乙個例子,將其改造為c庫的方式。

「mylib.c」檔案中:

#include 

#include

#include

#include

#include

#include

#include

/* 所有註冊給lua的c函式具有

* "typedef int (*lua_cfunction) (lua_state *l);"的原型。

*/static

int l_sin(lua_state *l)

/* 需要乙個"lual_reg"型別的結構體,其中每乙個元素對應乙個提供給lua的函式。

* 每乙個元素中包含此函式在lua中的名字,以及該函式在c庫中的函式指標。

* 最後乙個元素為「哨兵元素」(兩個"null"),用於告訴lua沒有其他的函式需要註冊。

*/static

const

struct lual_reg mylib = ,

};/* 此函式為c庫中的「特殊函式」。

* 通過呼叫它註冊所有c庫中的函式,並將它們儲存在適當的位置。

* 此函式的命名規則應遵循:

* 1、使用"luaopen_"作為字首。

* 2、字首之後的名字將作為"require"的引數。

*/extern

int luaopen_mylib(lua_state* l)

將」mylib.c」編譯為動態連線庫,

prompt> gcc mylib.c -fpic -shared -o mylib.so -wall

prompt> ls

mylib.c mylib.so a.lua

「a.lua」檔案中:

--[[ 這裡"require"的引數對應c庫中"luaopen_mylib()"中的"mylib"。

c庫就放在"a.lua"的同級目錄,"require"可以找到。]]

local mylib = require

"mylib"

-- 結果與上面的例子中相同,但是這裡是通過呼叫c庫中的函式實現。

print(mylib.mysin(3.14 / 2)) --> 0.99999968293183

1、每乙個與lua通訊的c函式都有其獨有的虛擬棧。

2、在極端情況下,列印指定目錄中檔案的例子可能會造成小小的記憶體洩漏。在記憶體空間不足的情況下,l_dir()中的lua_newtable()lua_pushstring()lua_settable()都會立即丟擲錯誤並終止程式的執行,這將導致closdir()無法被呼叫。

3、通常c庫中「特殊的函式」都被定義為公有的(使用extern修飾),而其他函式均被定義為私有的(使用static修飾)。

4、當你想要使用c函式擴充套件你的lua程式時,即使只有乙個c函式,也最好使用c庫的方式。因為在不久的將來(通常來說會很快),你將需要其他的c函式。

lua5 3異常機制

lua本質上利用c函式來操作lua虛擬機器。lua虛擬機器對於c來說只是在堆上的記憶體物件。lua有自己的執行物件 協程 每個協程有自己的呼叫棧。比如下面的函式 function add x,y return x y end如果x或y不能進行加法操作,在呼叫中就會產生異常。產生了異常,虛擬機器需要對...

快速掌握Lua 5 3 兩個完整的例子

將lua指令碼作為乙個小型的簡化版的 資料庫 展現了如何簡單高效的將這個 資料庫 中的資料轉化為網頁顯示。db.lua 檔案中內容。這裡看似是一張名為 entry 的表中儲存了許多資料,實際上在轉化程式中這時乙個名為 entry 的函式,引數是下面這個儲存了許多資料的 table 還記得 foo 與...

lua5 3資料結構

由於lua版本迭代之間,資料結構和函式都會部分變化 以下是我分析的lua.h中的資訊,以便確定版本 define lua version major 5 define lua version minor 3 define lua version num 503 define lua version ...