第一版是為 Lua 5.0 編寫的。儘管在很大程度上仍然適用於後續版本,但還是存在一些差異。
第四版針對 Lua 5.3,可在 Amazon 和其他書店購買。
購買此書,您還將幫助 支持 Lua 項目。
![]() |
Lua 編程 | ![]() |
第四部分。C API 第 26 章。從 Lua 呼叫 C |
作為第一個示例,讓我們看看如何實現一個簡化版本的函數,該函數返回給定數字的正弦值(更專業的實現應檢查其參數是否為數字)
static int l_sin (lua_State *L) { double d = lua_tonumber(L, 1); /* get argument */ lua_pushnumber(L, sin(d)); /* push result */ return 1; /* number of results */ }使用 Lua 註冊的任何函數都必須具有此相同原型,在
lua.h
中定義為 lua_CFunction
typedef int (*lua_CFunction) (lua_State *L);從 C 的角度來看,C 函數將 Lua 狀態作為其單個參數,並(在 C 中)返回一個整數,其中包含它正在返回的值的數量(在 Lua 中)。因此,函數不需要在推送其結果之前清除堆疊。在函數返回後,Lua 會自動移除結果下方堆疊中的任何內容。
在我們可以從 Lua 使用此函數之前,我們必須註冊它。我們使用 lua_pushcfunction
執行此神奇操作:它獲取一個指向 C 函數的指標,並創建一個類型為 "function"
的值來表示 Lua 中的此函數。測試 l_sin
的一種快速且簡便的方法是將其代碼直接放入 lua.c
檔案中,並在呼叫 lua_open
之後立即添加以下行
lua_pushcfunction(l, l_sin); lua_setglobal(l, "mysin");第一行推送一個函數類型值。第二行將其指定給全域變數
mysin
。在進行這些修改後,您重新建置您的 Lua 可執行檔;然後您可以在 Lua 程式中使用新的函數 mysin
。在下一節中,我們將討論將新的 C 函數與 Lua 連結的更好方法。
對於更專業的正弦函數,我們必須檢查其參數的類型。在此,輔助函式庫對我們有所幫助。luaL_checknumber
函數檢查給定的參數是否為數字:如果發生錯誤,它會擲出一個提供資訊的錯誤訊息;否則,它會返回該數字。我們函數中的修改很小
static int l_sin (lua_State *L) { double d = luaL_checknumber(L, 1); lua_pushnumber(L, sin(d)); return 1; /* number of results */ }使用上述定義,如果您呼叫
mysin('a')
,您會收到訊息
bad argument #1 to `mysin' (number expected, got string)請注意
luaL_checknumber
如何自動使用參數編號 (1)、函數名稱 ("mysin"
)、預期的參數類型 ("number"
) 和實際參數類型 ("string"
) 填寫訊息。
作為一個更複雜的範例,讓我們撰寫一個會傳回給定目錄內容的函式。Lua 沒有在標準函式庫中提供這個函式,因為 ANSI C 沒有這個工作的函式。這裡,我們會假設我們有一個符合 POSIX 的系統。我們的函式 dir
,會取得一個字串作為目錄路徑的引數,並傳回一個陣列,其中包含目錄項目。例如,一個呼叫 dir("/home/lua")
可能會傳回表格 {".", "..", "src", "bin", "lib"}
。如果發生錯誤,這個函式會傳回 nil 加上一個包含錯誤訊息的字串。
#include <dirent.h> #include <errno.h> static int l_dir (lua_State *L) { DIR *dir; struct dirent *entry; int i; const char *path = luaL_checkstring(L, 1); /* open directory */ dir = opendir(path); if (dir == NULL) { /* error opening the directory? */ lua_pushnil(L); /* return nil and ... */ lua_pushstring(L, strerror(errno)); /* error message */ return 2; /* number of results */ } /* create result table */ lua_newtable(L); i = 1; while ((entry = readdir(dir)) != NULL) { lua_pushnumber(L, i++); /* push key */ lua_pushstring(L, entry->d_name); /* push value */ lua_settable(L, -3); } closedir(dir); return 1; /* table is already on top */ }輔助函式庫中的
luaL_checkstring
函式,是字串的 luaL_checknumber
等效函式。
(在極端情況下,l_dir
的那個實作可能會造成一個小的記憶體外洩。它呼叫的 Lua 函式中有三個可能會因為記憶體不足而失敗:lua_newtable
、lua_pushstring
和 lua_settable
。如果這些呼叫中的任何一個失敗,它會引發一個錯誤並中斷 l_dir
,因此不會呼叫 closedir
。如同我們先前討論的,在大部分的程式中這不是一個大問題:如果程式用盡記憶體,它能做的最好的事就是關閉。不過,在 第 29 章 中,我們會看到一個避免這個問題的目錄函式替代實作。)
版權所有 © 2003–2004 Roberto Ierusalimschy。保留所有權利。 | ![]() |