此第一版是為 Lua 5.0 編寫的。儘管在很大程度上仍然適用於後續版本,但仍有一些差異。
第四版針對 Lua 5.3,可在 Amazon 和其他書店購買。
購買本書,您同時也能贊助 Lua 專案。
![]() |
程式設計 Lua | ![]() |
第四部分。C API 第 25 章。擴充應用程式 |
作為一個更進階的範例,我們將使用 C 中的 vararg
設施,為呼叫 Lua 函數建立一個包裝函數。我們的包裝函數(我們稱它為 call_va
)接收要呼叫的函數名稱、描述引數和結果型別的字串,然後接收引數清單,最後接收儲存結果的變數指標清單;它會處理 API 的所有細節。有了這個函數,我們可以將前一個範例簡寫成
call_va("f", "dd>d", x, y, &z);其中字串
"dd>d"
表示「兩個雙精度型態的引數,一個雙精度型態的結果」。此描述符可以使用字母 `d
´ 表示雙精度,`i
´ 表示整數,`s
´ 表示字串;`>
´ 將引數與結果分開。如果函數沒有結果,`>
´ 是可選的。
#include <stdarg.h> void call_va (const char *func, const char *sig, ...) { va_list vl; int narg, nres; /* number of arguments and results */ va_start(vl, sig); lua_getglobal(L, func); /* get function */ /* push arguments */ narg = 0; while (*sig) { /* push arguments */ switch (*sig++) { case 'd': /* double argument */ lua_pushnumber(L, va_arg(vl, double)); break; case 'i': /* int argument */ lua_pushnumber(L, va_arg(vl, int)); break; case 's': /* string argument */ lua_pushstring(L, va_arg(vl, char *)); break; case '>': goto endwhile; default: error(L, "invalid option (%c)", *(sig - 1)); } narg++; luaL_checkstack(L, 1, "too many arguments"); } endwhile: /* do the call */ nres = strlen(sig); /* number of expected results */ if (lua_pcall(L, narg, nres, 0) != 0) /* do the call */ error(L, "error running function `%s': %s", func, lua_tostring(L, -1)); /* retrieve results */ nres = -nres; /* stack index of first result */ while (*sig) { /* get results */ switch (*sig++) { case 'd': /* double result */ if (!lua_isnumber(L, nres)) error(L, "wrong result type"); *va_arg(vl, double *) = lua_tonumber(L, nres); break; case 'i': /* int result */ if (!lua_isnumber(L, nres)) error(L, "wrong result type"); *va_arg(vl, int *) = (int)lua_tonumber(L, nres); break; case 's': /* string result */ if (!lua_isstring(L, nres)) error(L, "wrong result type"); *va_arg(vl, const char **) = lua_tostring(L, nres); break; default: error(L, "invalid option (%c)", *(sig - 1)); } nres++; } va_end(vl); }儘管這個函數具有通用性,但它遵循我們前一個範例的步驟:它會推入函數、推入引數、執行呼叫,然後取得結果。它的程式碼大部分都很直接,但有一些細微差別。首先,它不需要檢查
func
是否是函數;lua_pcall
會觸發任何偶發錯誤。其次,因為它會推入任意數量的引數,所以它必須檢查堆疊空間。第三,因為函數可能會傳回字串,所以 call_va
無法從堆疊中彈出結果。在完成使用偶發字串結果(或將它們複製到其他緩衝區)後,由呼叫者彈出它們。
版權所有 © 2003–2004 Roberto Ierusalimschy。保留所有權利。 | ![]() |