第一版是為 Lua 5.0 所寫。雖然在很大程度上仍適用於後續版本,但有些地方有所不同。
第四版針對 Lua 5.3,可在 Amazon 和其他書店買到。
購買本書,您也可以 支持 Lua 專案。
![]() |
用 Lua 程式設計 | ![]() |
第四部分。C API 第 26 章。從 Lua 呼叫 C |
Lua 函式庫是一個區塊,定義了幾個 Lua 函式,並將它們儲存在適當的地方,通常是作為表格中的項目。Lua 的 C 函式庫模仿了這種行為。除了定義其 C 函式之外,它還必須定義一個特殊函式,對應於 Lua 函式庫的主區塊。呼叫此函式後,它會註冊函式庫的所有 C 函式,並將它們儲存在適當的地方。就像 Lua 主區塊一樣,它也會初始化函式庫中需要初始化的其他任何內容。
Lua 會透過這個註冊程序「看到」C 函式。一旦 C 函式在 Lua 中表示並儲存後,Lua 程式就會透過直接參考其位址(也就是我們在註冊函式時提供給 Lua 的內容)來呼叫它。換句話說,Lua 在註冊函式後,不會依賴函式名稱、套件位置或可見性規則來呼叫函式。通常,C 函式庫只有一個公開(extern)函式,也就是開啟函式庫的函式。所有其他函式都可以是私有的,在 C 中宣告為 static
。
當您使用 C 函式擴充 Lua 時,最好將您的程式碼設計為 C 函式庫,即使您只想註冊一個 C 函式:遲早(通常是早)您會需要其他函式。一如往常,輔助函式庫提供了一個輔助函式來執行此工作。luaL_openlib
函式接收一個 C 函式清單及其各自的名稱,並將它們全部註冊在一個具有函式庫名稱的表格中。舉例來說,假設我們要建立一個包含我們之前定義的 l_dir
函式的函式庫。首先,我們必須定義函式庫函式
static int l_dir (lua_State *L) { ... /* as before */ }接下來,我們宣告一個陣列,其中包含所有函式及其各自的名稱。此陣列具有
luaL_reg
類型的元素,這是一個具有兩個欄位的結構:一個字串和一個函式指標。
static const struct luaL_reg mylib [] = { {"dir", l_dir}, {NULL, NULL} /* sentinel */ };在我們的範例中,只有一個函式(
l_dir
)要宣告。請注意,陣列中的最後一對必須是 {NULL, NULL}
,以表示其結束。最後,我們使用 luaL_openlib
宣告一個主函式
int luaopen_mylib (lua_State *L) { luaL_openlib(L, "mylib", mylib, 0); return 1; }
luaL_openlib
的第二個引數是函式庫名稱。此函式會建立(或重複使用)一個具有給定名稱的表格,並使用 mylib
陣列指定的 name-function 對來填入表格。luaL_openlib
函式也允許我們為函式庫中的所有函式註冊常見的上值。目前,我們不使用上值,因此呼叫中的最後一個引數為零。luaL_openlib
在傳回時會在堆疊中留下它用來開啟函式庫的表格。luaopen_mylib
函式傳回 1 以將此值傳回 Lua。(與 Lua 函式庫一樣,此傳回是可選的,因為函式庫已經指定給一個全域變數。同樣地,就像在 Lua 函式庫中一樣,它不會花費任何成本,而且偶爾可能會很有用。)
完成函式庫後,我們必須將它連結到直譯器。如果你的 Lua 直譯器支援此功能,最方便的方法是使用動態連結功能。(請記住 第 8.2 節 中關於動態連結的討論。)在這種情況下,你必須使用你的程式碼建立一個動態函式庫(在 Windows 中為 .dll
檔案,在 Linux 中為 .so
檔案)。之後,你可以使用 loadlib
直接從 Lua 中載入你的函式庫。呼叫
mylib = loadlib("fullname-of-your-library", "luaopen_mylib")將
luaopen_mylib
函式轉換為 Lua 中的 C 函式,並將此函式指定給 mylib
。(這說明了為什麼 luaopen_mylib
必須與任何其他 C 函式具有相同的原型。)接下來,呼叫 mylib()
會執行 luaopen_mylib
,開啟函式庫。
如果你的直譯器不支援動態連結,則必須使用你的新函式庫重新編譯 Lua。除此之外,你需要一些方法來告訴獨立直譯器,它在開啟新狀態時應該開啟此函式庫。一些巨集可以簡化此任務。首先,你必須建立一個標頭檔(我們稱之為 mylib.h
),其內容如下
int luaopen_mylib (lua_State *L); #define LUA_EXTRALIBS { "mylib", luaopen_mylib },第一行宣告開啟函式。下一行將巨集
LUA_EXTRALIBS
定義為直譯器在建立新狀態時呼叫的函式陣列中的新項目。(此陣列的類型為 struct luaL_reg[]
,因此我們需要在那裡放置一個名稱。)
若要將此標頭檔包含在直譯器中,你可以在編譯器選項中定義巨集 LUA_USERCONFIG
。對於命令列編譯器,你通常必須新增一個選項,例如
-DLUA_USERCONFIG=\"mylib.h\"(反斜線保護殼層中的引號;當我們指定包含檔名稱時,在 C 中需要這些引號。)在整合開發環境中,你必須在專案設定中新增類似的內容。然後,當你重新編譯
lua.c
時,它會包含 mylib.h
,因此會在要開啟的函式庫清單中使用 LUA_EXTRALIBS
的新定義。
版權所有 © 2003–2004 Roberto Ierusalimschy。保留所有權利。 | ![]() |