一.配置Lua C++互動環境
1.下載Lua 包環境
地址: https://www.lua.org/download.html ,我們這裡用的是5.4.2版本。
2.新建C++ 控制檯應用程式
3.匯入Lua 原始碼
1)匯入Lua 原始碼到同級目錄(這樣做為了Main函式所在類新增Lua 的C 類的時候直接可以include,不需要考慮目錄層級問題)
開啟的目錄裡,將5.4.2 的lua包裡的 src目錄裡的檔案全部拷到此目錄
2)新增Lua 原始碼
選中剛剛匯入的Lua檔案
3)編譯
這時,點選目錄生成,回發現報錯
這是關鍵報錯資訊,重複main標頭檔案,眾所周知,main函式是啟動函式;那就註釋調main.
會發現,有兩處main ,lua.c 中 int main 和luac.c int main,分別都註釋了。(或者簡單粗暴,直接將luc.c和luac.c直接刪除也可以)
再點生成,成功。這兩處main,其實就是如果你將此lua編碼打包成exe,就是啟動函式。但是我們這裡不需要這邊的main,我們自己新建的C++ 應用程式,是有自己的Main。
二.Hello.lua 執行
新建Lua指令碼,必須.lua 結尾。
1.關鍵API
1)lua與C++互動,必須要一個虛擬棧。可通過lua_State* L = luaL_newstate(); 對於棧的介紹可參考:https://blog.csdn.net/shun_fzll/article/details/39120965,這裡就不對棧作描述了。
2)載入Lua檔案,可通過 luaL_dofile 返回一個 int型別,返回結果不為0,則表示異常
3)Lua有異常,會把返回結果返回到棧頂,也就是說報異常了,可以通過lua_tostring(L,-1)得到報啥錯,再列印出來.
4)lua_close 就是釋放這個棧。
5)對於C++呼叫 C的標頭檔案,需要extern
2.例項分析
1 #include <iostream> 2 #include <string.h> 3 using namespace std; 4 extern "C" 5 { 6 #include "lua.h" 7 #include "lualib.h" 8 #include "lauxlib.h" 9 } 10 int main() 11 { 12 std::cout << "Hello World!\n"; 13 lua_State* L = luaL_newstate(); 14 int Ret = luaL_dofile(L, "LuaHello.lua"); 15 if (Ret) 16 { 17 string strError = lua_tostring(L, -1); 18 cout << strError.c_str() << endl; 19 return -1; 20 } 21 22 lua_close(L); 23 return 0; 24 }
1)執行上述程式碼
2)想一下,好像lua程式碼是執行了,但是print怎麼會nil,並報錯,提示的還挺智慧,具體行號都報出來了。
我們再試著修改Lua程式碼中下移兩行試試:
3)咦,那就證明Lua檔案是肯定執行了,就是異常了。找不到print,print不是lua庫裡的函式嘛,為啥拿不到了。
因為C++環境中建立Lua_State這個棧,這個預設並沒有開啟lua標準庫。所以查一下。
在 上述Line:13 後面新增 luaL_openlibs(L);
執行 得到
恭喜,C++ 與Lua通訊成功。
三.Lua UserData應用例項
關於具體lua與C互動的一些常見操作,可參考:https://blog.csdn.net/shun_fzll/article/details/39120965
問題:有時候,你會想,我在C++中宣告瞭一個struct,在lua中,也想宣告這個struct,怎麼弄納?接下來這個案例就是教你如何使。
我們的UserData就是解決這個問題的。
Lua UserData分兩種,我們這說的是FullUserData,就是可以解決上述問題的UserData.
直奔主題,看程式碼分析。
Lua5.1之前和之後的註冊函式差距很大,詳情可參考:https://blog.csdn.net/ljhjason/article/details/28860633
Lua5.1之後可以使用 luaL_requiref 代替 Lua5.1之前的luaL_register ,可參考:https://blog.csdn.net/ljhjason/article/details/28860633
1 #include <iostream> 2 #include <string.h> 3 using namespace std; 4 extern "C" 5 { 6 #include "lua.h" 7 #include "lualib.h" 8 #include "lauxlib.h" 9 } 10 11 struct TestCStruct 12 { 13 char* Name; 14 int Num = 1; 15 }; 16 17 int NewTestCStruct(lua_State* L) 18 { 19 size_t iBytes = sizeof(struct TestCStruct); 20 struct TestCStruct* pStruct = (struct TestCStruct*)lua_newuserdata(L, iBytes); 21 return 1; 22 } 23 24 int SetNum(lua_State* L) 25 { 26 struct TestCStruct *pStruct = (struct TestCStruct*)lua_touserdata(L, 1); 27 luaL_argcheck(L, pStruct != NULL, 1, "Error Param"); 28 int num = luaL_checkinteger(L, 2); 29 luaL_argcheck(L, num > 0, 2,"Wrong Paramter"); 30 pStruct->Num = num; 31 return 1; 32 } 33 34 int GetNum(lua_State* L) 35 { 36 struct TestCStruct *pStruct = (struct TestCStruct*)lua_touserdata(L, 1); 37 luaL_argcheck(L, pStruct != NULL, 1, "ErrorStruct"); 38 lua_pushinteger(L, pStruct->Num); 39 return 1; 40 } 41 42 struct luaL_Reg arrayFunc[] = { 43 {"new",NewTestCStruct}, 44 {"SetNum",SetNum}, 45 {"SNum",GetNum}, 46 {NULL,NULL} 47 }; 48 49 LUALIB_API int luaopen_mytest(lua_State* L) 50 { 51 luaL_newlib(L, arrayFunc); 52 return 1; 53 } 54 55 int main() 56 { 57 std::cout << "Hello World!\n"; 58 lua_State* L = luaL_newstate(); 59 luaL_openlibs(L); 60 luaL_requiref(L, "mytest", luaopen_mytest, 0); 61 int Ret = luaL_dofile(L, "LuaHello.lua"); 62 if (Ret) 63 { 64 string strError = lua_tostring(L, -1); 65 cout << strError.c_str() << endl; 66 return -1; 67 } 68 69 lua_close(L); 70 return 0; 71 }
Lua中原始碼
local t = require("mytest") print("t:" .. tostring(t)) local y = t.new() print("y :" .. tostring(y)) t.SetNum(y,100) print("Num:" ..t.SNum(y)) local y2 = t.new() print("y2 :" .. tostring(y2)) print("Hello lua and C++")
執行結果
綜上, 可以看到Full UserData 的使用,主要核心是Line:60 luaL_requiref的使用。