Lua中呼叫C函式

2021-09-06 17:16:46 字數 3368 閱讀 9340

lua利用乙個虛擬的堆疊來給c傳遞值或從c獲取值。每當lua呼叫c函式,都會獲得乙個新的堆疊,該堆疊初始包含所有的呼叫c函式所需要的引數值(lua傳給c函式的呼叫實參),並且c函式執行完畢後,會把返回值壓入這個棧(lua從中拿到c函式呼叫結果)。

(1)typedef struct lua_state lua_state;

lua虛擬機器(或叫直譯器),可以理解為乙個thread,和乙個完整的lua虛擬環境的執行狀態。

(2)typedef int (*lua_cfunction) (lua_state *l);

能夠被lua呼叫的c函式都必須是這種規則。函式的返回的int值表示c函式返回值的個數。

(3)void lua_pushcclosure (lua_state *l, lua_cfunction fn, int n);

將乙個c閉包壓棧;

首先將upvalues依次壓棧,然後呼叫該函式,將c函式壓棧,並將n個upvalues出棧;

引數fn:c函式指標

引數n:函式關聯的upvalue的個數。

(4)void lua_pushcfunction (lua_state *l, lua_cfunction f);

將c函式壓棧;

接收乙個c函式的指標引數,然後將乙個lua.function型別的物件壓棧。

(5)void lua_register (lua_state *l, const char *name, lua_cfunction f);

註冊c函式為乙個全域性變數;

#define lua_register(l,n,f) (lua_pushcfunction(l, f), lua_setglobal(l, n))

(6)void lual_setfuncs (lua_state *l, const lual_reg *l, int nup);

註冊函式到棧頂的表中;

引數l:lual_reg列表,記錄了要註冊的函式資訊,注意,該列表以結尾;

nup引數:upvalue的個數,如果不為0,則註冊的所有函式都共享這些upvalues;

先將table壓棧,然後將upvalues依次壓棧,然後呼叫該函式進行函式註冊。註冊完畢後upvalues會出棧。

注意:lual_register函式已經不再使用,取而代之的是lual_setfuncs,因為該函式不會建立全域性變數。

typedef struct lual_reg lual_reg;

lua可以呼叫c函式的能力將極大的提高lua的可擴充套件性和可用性。對於有些和作業系統相關的功能,或者是對效率要求較高的模組,我們完全可以通過c函式來實現,之後再通過lua呼叫指定的c函式。對於那些可被lua呼叫的c函式而言,其介面必須遵循lua要求的形式,即typedef int (*lua_cfunction)(lua_state* l)。簡單說明一下,該函式型別僅僅包含乙個表示lua環境的指標作為其唯一的引數,實現者可以通過該指標進一步獲取lua**中實際傳入的引數。返回值是整型,表示該c函式將返回給lua**的返回值數量,如果沒有返回值,則return 0即可。需要說明的是,c函式無法直接將真正的返回值返回給lua**,而是通過虛擬棧來傳遞lua**和c函式之間的呼叫引數和返回值的。這裡我們將介紹兩種lua呼叫c函式的規則。

1. c函式作為應用程式的一部分

#include #include 

#include

#include

#include

//待lua呼叫的c註冊函式。

static

int add2(lua_state*l)

//另乙個待lua呼叫的c註冊函式。

static

int sub2(lua_state*l)

const

char* testfunc = "

print(add2(1.0,2.0)) print(sub2(20.1,19))";

intmain()

2. c函式庫成為lua的模組

將包含c函式的**生成庫檔案,如linux的so,或windows的dll,同時拷貝到lua**所在的當前目錄,或者是lua_cpath環境變數所指向的目錄,以便於lua解析器可以正確定位到他們。在我當前的windows系統中,我將其copy到"c:\program files\lua\5.1\clibs\",這裡包含了所有lua可呼叫的c庫。見如下c語言**和關鍵性注釋:

#include #include 

#include

#include

#include

//待註冊的c函式,該函式的宣告形式在上面的例子中已經給出。

//需要說明的是,該函式必須以c的形式被匯出,因此extern "c"是必須的。

//函式**和上例相同,這裡不再贅述。

extern"c

"int add(lua_state*l)

extern"c

"int sub(lua_state*l)

//lual_reg結構體的第乙個欄位為字串,在註冊時用於通知lua該函式的名字。

//第乙個欄位為c函式指標。

//結構體陣列中的最後乙個元素的兩個欄位均為null,用於提示lua註冊函式已經到達陣列的末尾。

static lual_reg mylibs =,

,}; //

該c庫的唯一入口函式。其函式簽名等同於上面的註冊函式。見如下幾點說明:

//1. 我們可以將該函式簡單的理解為模組的工廠函式。

//2. 其函式名必須為luaopen_***,其中***表示library名稱。lua**require "***"需要與之對應。

//3. 在lual_register的呼叫中,其第乙個字串引數為模組名"***",第二個引數為待註冊函式的陣列。

//4. 需要強調的是,所有需要用到"***"的**,不論c還是lua,都必須保持一致,這是lua的約定,

//否則將無法呼叫。

extern"c

"__declspec(dllexport)

int luaopen_mytestlib(lua_state*l)

見如下lua**:

require

"mytestlib"--

指定包名稱

--在呼叫時,必須是package.function

print(mytestlib.add(1.0,2.0

))print(mytestlib.sub(20.1,19))

參考:

C中呼叫Lua函式

我們先來看乙個簡單的例子 lua state l null 內部呼叫lua函式 double f double x,double y int main void functest.lua f function a,b return a b end 這其中最關鍵的是呼叫函式的使用,在c中呼叫lua函式...

lua呼叫c函式

最近在進入lua程式設計的狀態,一度令我困惑的是,lua提供的功能少的可憐,跟自備電池的python相比,可說是簡陋了。連table的列印,都需要自己實現,也因此有了一打的第三方方案。後來我想明白了,以lua和c如此緊密的關係,只需要建立lua的binding,那麼豐富而效能強大的c庫資源完全可以為...

lua呼叫c函式

lua可以呼叫c函式的能力將極大的提高lua的可擴充套件性和可用性。對於有些和作業系統相關的功能,或者是對效率要求較高的模組,我們完全可以通過c函式來實現,之後再通過lua呼叫指定的c函式。對於那些可被lua呼叫的c函式而言,其介面必須遵循lua要求的形式,即 typedef int lua cfu...