LUA與C++互動第一篇
到公司已經兩個周了,學習Lua已經開始在專案中使用,但是由於使用的lua函式基本上都是公司在上面進行了一次封裝的,沒有原始碼對兩種語言的互動詳情還是不甚瞭解。如:如果向LUA註冊一個物件給LUA使用,如何呼叫LUA中函式這些在公司的SDK看來就是一個簡單的RegisterObject物件的幾個屬性進行填寫就行了。
今天主要是對在Lua中如何呼叫C++函式和在C++中如何呼叫Lua函式進行學習。
在LUA中要呼叫C++函式,那就要在C++中對Lua進行註冊,如何註冊呢?需要一個巨集來完成功能,就是lua_register(L,"add",add),該巨集對應的是兩個函式,一個是lua_pushcfunction(L,f),lua_setglobal(L,n);可以看出是先對函式進行壓棧、然後給函式設定一個在lua中的呼叫名稱,注意此處的n不是表示一個整數什麼的,是name的意思,表示函式的註冊名。而此處lua_setglobal也是一個巨集,
#define lua_setglobal(L,s) lua_setfield(L, LUA_GLOBALSINDEX, s)
可以看出其實lua_setglobal只是lua_setfield的一個特例,因為LUA_GLOBALSINDEX是一直存在的,所以使用幹函式來簡單操作,當然如果我們要註冊的函式不註冊到全域性的,而是在其他某個我們定義的表內可訪問,那就要呼叫lua_setfield函式了。說到這個話題,設計到的函式就會越來越多,比如lua_getglobal與lua_setglobal對於,lua_getfield與lua_getfield對應,我們用到的時候再解釋,不用到時就不說了。
上面提到了使用lua_register函式進行註冊,這裡要強調的是該函式對註冊的函式原型是有要求的,不是任何函式都可以註冊,函式原型如下:
int (func*)(lua_State* L);我們應該能夠理解,LUA和C++的互動通過棧來進行傳參,因此只需要給一個引數lua_State表當前操作棧就行了,至於該函式有幾個引數,返回值這些在func函式中去處理就好了,該函式返回值表示C++函式會向棧中放多少個值,而至於需要幾個引數可以通過lua_tostring、lua_tointeger等函式通過傳入棧中的序號來獲取。由於註冊函式原型固定了,但我們在寫C++函式的時候不可能程式碼長短什麼的都往該函式中塞,在實際中我們常常是隻使用該函式來獲取從LUA讀取引數和返回引數,所以該函式一般是這樣的形式:
int funcname(lua_State* L)
{
//此處可以做資料型別檢查這些
..
//取值
arg1 = lua_tostring(L,-1);
arg2 = lua_tostring(L,-2);
//呼叫真正的函式
dosomething_function
//進行引數壓棧等也可以再上面呼叫的函式中壓棧
return n;//此處的n是C++向棧中壓入的引數個數,如果和壓入棧個數不一致,可能導致棧失衡
}
註冊函式來說就上面幾個步驟而已,比起註冊C++類來說簡單得多,註冊C++類現在我也還沒有掌握,在此處就不說了,下面說的是我們註冊了C++函式現在該到LUA中去呼叫了,現在在test.lua檔案中新增這樣一個函式
function lua_add(a,b)
return add(a,b)
end
現在如果在命令列執行該檔案應該會失敗,因為我上面註冊的C++函式不是註冊成一個動態庫,我是直接在控制檯可執行檔案中寫的,因此我就需要在
C++中來呼叫該lua_add函式了。C++中需要先知道有lua_add這樣一個函式,需要先使用luaL_dofile(test.lua)來載入該檔案,載入進去後該函式就存在於全域性表中了,於是使用lua_getglobal函式來從表中獲取函式地址lua_getglobal(L,"lua_add"),該函式是在全域性表中查詢lua_add函式並把它壓到棧頂,到這裡剛開始學習的時候會很疑惑,當初我看lua中很多函式介紹的時候就覺得很不解,很多函式就是對棧操作,單獨看一個函式實在看不出想達到什麼目的,但和其他函式配合使用功能就強大了,所以需要對lua中這些對棧操作的函式都有一個認識,才能夠組合出自己需要的功能來。前面說把函式找到壓棧了,下面就是要呼叫函式,呼叫函式前需要傳引數,如何傳?還是把引數放到棧中、如果我們需要給函式傳兩個引數,把連個引數壓棧,使用函式lua_pushinteger(L,4)表示向棧中壓入一個整數4,其他型別如lua_pushstring,lua_pushlstring等很多。引數也進棧了,下面才是開始真正呼叫,如何調?lua提供的函式lua_pcall來呼叫,該函式第一個引數為lua_State表示當前的棧吧,第二個參數列示要呼叫函式的引數個數,第三個表示被呼叫函式的返回值個數,這個不要想C++中函式只有一個返回值,這是表示我們要向lua中返回多少個值;第四個參數列示錯誤處理函式在棧上的索引,為0表示沒有錯誤處理函式,和lua_pcall一樣用於呼叫棧中函式的函式有lua_call和lua_cpcall等,這裡不仔細介紹。在上面的函式呼叫中,由於返回值存在與棧中,在取回返回值後,需要呼叫lua_pop(L)對棧進行清空。
下面是一個測試程式碼:
- #include <stdio.h>
- extern "C"
- {
- #include <lua.h>
- #include <lualib.h>
- #include <lauxlib.h>
- }
- #include <string>
- using namespace std;
- int add(lua_State* L)
- {
- int a = lua_tointeger(L,1);//取得函式引數
- int b = lua_tointeger(L,2);
- lua_pushinteger(L,a+b);//入棧返回值
- return 1;//1表示壓入棧資料個數
- }
- struct luaL_Reg luaCppReg[] =//可以使用該結構體一次註冊多個函式,則需要呼叫luaL_register函式,此處沒有使用
- {
- {"add",add},
- {NULL,NULL}
- };
- int _tmain(int argc, _TCHAR* argv[])
- {
- char buff[256];
- int error;'
- lua_State *L = luaL_newstate(); /* opens Lua,由於我使用的是lua5.2版本,lua_open函式不存在了 */
- luaopen_base(L); /* opens the basic library 這些是在引入一些庫,就如如果add函式在編譯成dll後如果在lua中要使用需要require “動態庫名"一樣*/
- luaopen_table(L); /* opens the table library這些庫是加在這裡只是測試 */
- luaopen_io(L); /* opens the I/O library */
- luaopen_string(L); /* opens the string lib. */
- luaopen_math(L); /* opens the math lib. */
- lua_register(L,"add",add);//註冊add函式,好像還可以使用luaL_register函式註冊,該函式使用結構體的方式
- luaL_dofile(L,"test.lua");//載入lua檔案,回將裡面的函式載入到全域性表中
- lua_getglobal(L,"lua_add");//查詢lua_add函式,並壓入棧底
- lua_pushinteger(L,6);//函式引數1
- lua_pushinteger(L,5);//函式引數2
- lua_pcall(L,2,1,0);//呼叫lua_add函式,同時會對lua_add及兩個參加進行出棧操作,並壓入返回值
- int result = lua_tointeger(L,-1);//從棧中取回返回值
- lua_pop(L,1);//清棧,由於當前只有一個返回值
- printf("result = %d",result);
- lua_close(L);//關閉lua環境
- return 0;
- }
相關文章
- Lua C++互動 應用例項步驟(UserData使用)C++
- QT QML模組與C++的互動QTC++
- C++呼叫LuaC++
- c++ 鍵盤/滑鼠互動C++
- Android 與 LuaAndroid
- C++ 與 QML 之間進行資料互動的幾種方法C++
- js 與WKWebView 互動JSWebView
- C++中UNIX時間戳與日期互轉C++時間戳
- Java與Excel的互動!-JavaExcel
- ReactNative與iOS的互動ReactiOS
- Flutter 與Native原生互動Flutter
- Flutter 與 Android 的互動FlutterAndroid
- flash如何與js互動?JS
- Spring 容器與 Servlet互動SpringServlet
- ajax與XML檔案互動XML
- Android webview 與 js(Vue) 互動AndroidWebViewJSVue
- Android與WebView資料互動AndroidWebView
- Flutter使用JsBridge與WebView互動FlutterJSWebView
- 【unity2022與html互動】UnityHTML
- H5 與 APP 互動!H5APP
- C#與Python互動方式C#Python
- Vulkan與DX11互動
- 筆記:前端與後臺互動筆記前端
- php與ethereum客戶端互動PHP客戶端
- Http(s)與後臺互動方式HTTP
- Hive 與 ElasticSearch 的資料互動HiveElasticsearch
- python SQL基礎與python互動PythonSQL
- React Native與Android通訊互動React NativeAndroid
- 隨機與和未知的互動隨機
- python與mysql資料庫互動PythonMySql資料庫
- 與Linux進行基礎互動Linux
- 編譯lua動態庫編譯
- 互動視訊不能為了互動而互動
- 與低層次互動活動相比,深層次互動活動的參與頻率更高(附原資料表)
- web與APP之間的互動—WebViewJavascriptBridgeAPPWebViewJavaScript
- [譯]Unsafe Swift – 指標與C互動Swift指標
- Flutter WebView與JS互動簡易指南FlutterWebViewJS
- PHP與Python進行資料互動PHPPython
- Python高階 -- 08 MySQL與Python互動PythonMySql