Lua C++互動 應用例項步驟(UserData使用)

不三週助發表於2021-03-01

一.配置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的使用。

https://files.cnblogs.com/files/u3ddjw/TestLuaAndC.rar

相關文章