首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C 語言調用 Lua 函數完整流程:棧操作、錯誤處理、封裝範例

     編輯:關於C語言

C 語言調用 Lua 函數完整流程

Lua 作為嵌入式腳本語言,核心 API 基於虛擬棧交互。調用 Lua 函數遵循固定四步驟:**壓入函數 → 壓入參數 → 執行調用 → 彈出結果**。本文給出標準流程、錯誤處理模式、類型轉換表與可復用封裝函數。

標準四步驟

  1. lua_getglobal(L, "func_name") — 將全局函數壓棧
  2. lua_pushnumber(L, arg) / lua_pushstring / lua_pushboolean … — 依序壓入參數
  3. lua_pcall(L, nargs, nresults, errfunc) — 受保護調用
      nargs 參數個數,nresults 期望結果數,errfunc 錯誤處理函數索引 (0 表示無)
  4. 從棧頂取結果:lua_tonumber(L, -1)、lua_tostring(L, -1)… 然後 lua_pop(L, nresults)

完整封裝範例:調用 f(x, y) = (x^2 * sin(y)) / (1 - x)

/* 假設 Lua 狀態機 L 已創建並加載腳本 */
double call_f(lua_State *L, double x, double y) {
    lua_getglobal(L, "f");           // 1. 函數
    lua_pushnumber(L, x);            // 2. 參數 1
    lua_pushnumber(L, y);            //    參數 2

    if (lua_pcall(L, 2, 1, 0) != LUA_OK) {  // 3. 調用
        const char *err = lua_tostring(L, -1);
        fprintf(stderr, "Lua error: %s\n", err);
        lua_pop(L, 1);               // 彈出錯誤信息
        return NAN;
    }

    if (!lua_isnumber(L, -1)) {      // 4. 類型檢查
        fprintf(stderr, "f() must return a number\n");
        lua_pop(L, 1);
        return NAN;
    }
    double z = lua_tonumber(L, -1);
    lua_pop(L, 1);                   // 清理棧
    return z;
}

關鍵 API 速查表

操作API備註
壓入全局函數lua_getglobal(L, name)同名變量非函數會報錯
壓入數字lua_pushnumber(L, n)Lua 5.3+ 整數用 lua_pushinteger
壓入字符串lua_pushlstring(L, s, len)二進制安全
受保護調用lua_pcall(L, nargs, nresults, msgh)返回 LUA_OK 成功,否則錯誤碼
檢查類型lua_isnumber/string/boolean/table/function
取數字lua_tonumber(L, idx)idx=-1 為棧頂
取字符串lua_tolstring(L, idx, &len)指針屬於 Lua,勿 free
彈出棧頂lua_pop(L, n)宏定義 lua_settop(L, -n-1)

錯誤處理最佳實踐

  • 必須用 lua_pcall,不要用 lua_call (會長跳出導致 C 棧展開失敗)。
  • 錯誤函數:傳入 msgh 索引可自定義堆棧追蹤,常用 luaL_traceback。
  • 檢查返回類型:Lua 動態類型,調用後務必 lua_is* 驗證。
  • 棧平衡:每次調用結束確保棧頂恢復調用前高度,否則棧溢出/洩漏。

多返回值處理

-- Lua: function g() return 1, "hello", true end
lua_getglobal(L, "g");
lua_pcall(L, 0, 3, 0);  // 期望 3 個結果
int n = lua_tonumber(L, -3);      // 底部第一個
const char *s = lua_tostring(L, -2);
int b = lua_toboolean(L, -1);
lua_pop(L, 3);

注意:多返回值中第一個最先壓入,棧頂是最後一個。

進階:註冊 C 函數供 Lua 調用

static int l_sin(lua_State *L) {
    double d = luaL_checknumber(L, 1);
    lua_pushnumber(L, sin(d));
    return 1;  // 返回值個數
}
lua_register(L, "c_sin", l_sin);  // Lua 中可直接 c_sin(3.14)

小結

C 調用 Lua 核心是棧協議:壓函數、壓參數、lua_pcall、取結果、清棧。封裝通用 call_lua_func 並嚴格檢查類型與錯誤碼,即可構建穩健的 C/Lua 雙向互調層。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved