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

Lua 與 C++ 交互實戰:從環境配置到數據傳遞全流程

     編輯:關於C++

上一篇介紹了 Lua C API 基礎,本文將通過完整的 Visual Studio 專案實戰,演示如何搭建 C++ 嵌入 Lua 環境,實現腳本加載執行、雙向函數調用、參數傳遞與返回值獲取等核心交互功能。

一、Visual Studio 專案配置 Lua 開發環境

  1. 新建 C++ 控制台專案(如 lua1)
  2. 將 Lua 安裝目錄下的 include、lib 資料夾複製到專案根目錄(與 .sln 同級)
  3. 專案屬性 → C/C++ → 附加包含目錄:添加 ../include
  4. 專案屬性 → 鏈接器 → 附加庫目錄:添加 ../lib
  5. 代碼中通過 extern "C" 包含 Lua 頭文件,並用 #pragma comment(lib, "lua5.1.lib") 鏈接庫

Lua include/lib 目錄

複製到專案目錄

專案屬性頁面

附加包含目錄配置

附加庫目錄配置

二、基礎示例:加載並執行 Lua 腳本文件

// lua1.cpp
#include "stdafx.h"
#include <iostream>
#include <stdio.h>
#include <string.h>

extern "C" {
    #include "lua.h"
    #include "lauxlib.h"
    #include "lualib.h"
}

using namespace std;
#pragma comment(lib, "lua5.1.lib")

int _tmain(int argc, _TCHAR* argv[]) {
    char buff[256];
    int error;

    // 1. 創建 Lua 狀態機(虛擬棧)
    lua_State* L = luaL_newstate();
    // 2. 打開標準庫
    luaL_openlibs(L);

    // 3. 加載 Lua 文件並編譯為代碼塊
    char fileName[] = "F:/LuaFile/lua1.lua";
    luaL_loadfile(L, fileName);

    // 4. 執行代碼塊
    int result = lua_pcall(L, 0, LUA_MULTRET, 0);
    if (!result) {
        printf_s("Lua 腳本運行成功\n");
    }

    // 5. 關閉狀態機
    lua_close(L);
    return 0;
}

Lua 腳本 lua1.lua:

print("I am lua1")

Lua 腳本內容

運行結果

關鍵 API 解析:

  • luaL_newstate:創建獨立 Lua 狀態機(虛擬棧)
  • luaL_openlibs:載入標準庫(base, string, table, math 等)
  • luaL_loadfile:讀取文件、語法分析、編譯為字節碼塊壓棧
  • lua_pcall:受保護調用執行棧頂代碼塊,參數含義:(L, nargs, nresults, errfunc)
  • lua_close:銷毀狀態機,釋放所有資源

三、數據輸入:動態編譯執行用戶輸入/字符串

使用 luaL_loadbuffer 直接編譯內存字符串:

int _tmain(int argc, _TCHAR* argv[]) {
    char buff[256];
    int loadError, callError;
    lua_State* L = luaL_newstate();
    luaL_openlibs(L);

    // 方式一:從 stdin 逐行讀取並執行
    while (fgets(buff, sizeof(buff), stdin) != NULL) {
        loadError = luaL_loadbuffer(L, buff, strlen(buff), "line");
        if (loadError) {
            printf_s("%s\n", lua_tostring(L, -1));
            lua_pop(L, 1);
        }
        callError = lua_pcall(L, 0, 0, 0);
        if (callError) {
            printf_s("%s\n", lua_tostring(L, -1));
            lua_pop(L, 1);
        }
    }
    lua_close(L);
    return 0;
}

交互式輸入運行結果

方式二:C++ 長字符串直接作為代碼塊:

string luaBuff = "print('hello world');"
    "local a = 123;"
    "print(type(a));"
    "local b = 'ABC';"
    "print(type(b));"
    "function d(...)"
    "local str = 'abc^%&(';"
    "print(string.gsub(str, '%w', ''));"
    "end;"
    "d();";

loadError = luaL_loadbuffer(L, luaBuff.c_str(), strlen(luaBuff.c_str()), "line");
// ... 執行流程同上

字符串代碼塊執行結果

四、C++ 與 Lua 雙向函數調用

核心機制:全局表作為雙方通信的橋樑。

  • C++ → Lua:lua_pushcfunction 壓入 C 函數指針 → lua_setglobal 註冊全局名
  • Lua → C++:lua_getglobal 獲取全局函數 → lua_pcall 調用
  • 關鍵順序:必須先 lua_pcall 執行主腳本塊(定義 Lua 函數),再註冊/獲取全局函數

C++ 代碼:

void fun1(lua_State* L) {
    printf_s("I am fun1, I'll call fun3\n");
    lua_getglobal(L, "fun3");
    int callError = lua_pcall(L, 0, 0, 0);
    if (callError) { /* 錯誤處理 */ }
}

int fun2(lua_State* L) {
    printf_s("I am fun2~~~~~~~~~\n");
    return 0; // 返回值個數
}

int _tmain(...) {
    lua_State* L = luaL_newstate();
    luaL_openlibs(L);
    luaL_loadfile(L, "F:/LuaFile/lua1.lua");
    
    // 註冊 C++ 函數給 Lua
    lua_pushcfunction(L, fun2);
    lua_setglobal(L, "fun2");
    
    // 執行主腳本(定義 fun3, fun4)
    lua_pcall(L, 0, 0, 0);
    
    // C++ 調用 Lua 函數
    fun1(L);
    lua_close(L);
    return 0;
}

Lua 腳本:

function fun3()
    print("I am fun3, I'll call fun2")
    fun2()  -- 調用 C++ 註冊的 fun2
end

function fun4()
    print("I am fun4")
    fun2()
end

fun4()  -- 主腳本執行入口

Lua 腳本雙向調用定義

雙向調用運行結果

五、函數參數傳遞與返回值處理

基於 虛擬棧 的先進後出特性:

  • C++ 調用 Lua:lua_getglobal 取函數 → lua_pushnumber 壓入參數 → lua_pcall(L, nargs, nresults, 0) → lua_tonumber(L, -1) 取返回值
  • Lua 調用 C++:C 函數參數 lua_State* L → luaL_checkstring(L, 1) 取第 1 參數 → lua_pushstring 壓返回值 → return nresults

修改後的 C++ 關鍵片段:

void fun1(lua_State* L) {
    lua_getglobal(L, "fun3");
    lua_pushnumber(L, 2);  // 參數 1
    lua_pushnumber(L, 5);  // 參數 2
    int callError = lua_pcall(L, 2, 1, 0); // 2 參數,1 返回值
    if (!callError) {
        int returnNum = lua_tonumber(L, -1);
        printf_s("fun3 return num: %d\n", returnNum);
    }
}

int fun2(lua_State* L) {
    const char* paramStr = luaL_checkstring(L, 1);
    printf_s("I get the str: %s\n", paramStr);
    lua_pop(L, 1); // 彈出參數
    lua_pushstring(L, "fun2 getted the param.");
    return 1; // 1 個返回值
}

修改後的 Lua 腳本:

function fun3(a, b)
    print("fun3 received:", a, b)
    return a + b
end

function fun4(str)
    print("fun4 received:", str)
    local ret = fun2(str) -- 調用 C++ fun2
    print("fun2 returned:", ret)
end

帶參數返回值的 Lua 腳本

參數返回值運行結果

總結

本文完整演示了 C++ 嵌入 Lua 的全流程:環境搭建 → 腳本加載執行 → 動態代碼編譯 → 雙向函數調用 → 參數/返回值傳遞。掌握棧操作(壓入/彈出/索引)與 lua_pcall 參數含義是核心。後續將介紹 Table、用戶數據、元表等高級交互主題。

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