日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++和Lua交互教程(基于LuaBridge)

發布時間:2024/9/27 c/c++ 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++和Lua交互教程(基于LuaBridge) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

作者:查志旺 ,向日葵遠程控制軟件前端開發工程師。

最近公司需要做向日葵遠程控制軟件跨平臺項目,為了代碼的可復用性,需嵌入跨平臺腳本語言,我們選擇了Lua,理由是Lua由標準C編寫而成,幾乎在所有操作系統和平臺上都可以編譯,Lua腳本可以很容易的被C/C++ 代碼調用,也可以反過來調用C/C++的函數,今天就跟大家分享下c++與Lua交互的一些問題。

為了方便c++和lua的交互,我引進了LuaBridge。因為它源碼簡單易用,只有頭文件,沒有.cpp文件,不需要編譯,只需要引用頭文件即可,方便快捷。

下面我用vs2008工具寫了一個win32控制臺項目例子來講解下c++和Lua簡單的互調。

一、準備工作

從lua官網上下載最新的http://www.lua.org/download.html,下個最新的lua-5.3.4.tar.gz解壓出來后可以直接拿源碼編譯成lib或者直接加入到項目中.我是直接把它放到項目中,編譯的時候,會出現多個main函數入口的錯誤(移除對應的文件)。

下載LuaBridge,下載地址:https://github.com/vinniefalco/LuaBridge列表下的Source/LuaBridge是源碼,Manual.html是幫助文檔。

創建win32控制臺項目test_lua把lua源碼和LuaBridge頭文件放入到項目目錄下并添加到項目工程中。

二、編寫代碼

1、先引用Lua和LuaBridge頭文件如下:

//引用c文件的頭文件所以需要加上extern "C" extern "C" {#include "lua.h"#include "lauxlib.h"#include "lualib.h" } #include "LuaBridge\LuaBridge.h"

2、然后創建test_lua類和一個子類代碼如下:

class test_lua { public:test_lua(){m_test_string = "c++ test string";}~test_lua(){} //test方法void test(int a,int b){printf("c++ test function %d+%d=%d\n", a, b, a+b);}//屬性set方法void SetName(std::string name){m_name = name;} //屬性get方法,注意需要后面加conststd::string GetName() const{return m_name;} //供lua調用方法,返回多個參數方法int cFunc(lua_State* L){ //返回參數1lua_pushstring(L,"str1"); //返回參數1lua_pushstring(L,"str2"); //返回參數個數return 2;}std::string m_test_string;std::string m_name;static int m_static_data; }; //test_lua靜態變量定義(靜態變量在類內只是聲明) int test_lua::m_static_data; //test_lua子類 class test_lua_child :public test_lua {public:test_lua_child(std::string test):m_test_child_string(test){printf("call test_lua_child constructor\n");}~test_lua_child(){}std::string m_test_child_string; };

3、創建一個lua腳本文件a.lua內容為:

--lua 打印lua script print("lua script") --調用成員變量m_test_string(test_str為注冊的名字) print(test_lua.test_str) --調用c++靜態變量(需要加上test命名空間) test.test_lua.static_data=12 print("static_data: "..test.test_lua.static_data) --調用c++類test_lua屬性name test_lua.name="name_property"; print("name: "..test_lua.name); --lua調用c++方法test_lua為c++類在lua的注冊名,調用test方法 test_lua:test(3,4)--調用c++調用方法返回多個值 local ret1,ret2 = test_lua:cFunc() print("ret1="..ret1.." ret2="..ret2)--創建test_lua_child對象 local test_lua_child = test.test_lua_child("test_string") --調用其變量 print("child string:"..test_lua_child.test_child_string); --調用父類的name屬性 test_lua_child.name="child_name_property"; print("name:"..test_lua_child.name);--lua 方法加法 function lua_add_function(a,b)print("lua_add_function") return a+b; end--lua 方法字符串加法(..是相加語法) function lua_add_str_function(a,b)print("lua_add_str_function") return a..b; end

4、主函數編寫

4.1、Lua的初始化和加載Lua的基本庫

//初始化Lua (最后記得調用lua_close(lua_state)釋放)lua_State* lua_state = luaL_newstate(); //加載Lua基本庫luaL_openlibs(lua_state);

4.2、用luabridge注冊到lua中

在這里要注意的是多個類注冊需要加一個namespace(test),且.endClass()后面不加分號

luabridge::getGlobalNamespace(lua_state).beginNamespace("test").beginClass<test_lua>("test_lua").addConstructor<void (*) (void)> ()//無參構造函數的注冊.addData("test_str",&test_lua::m_test_string)//注冊變量到lua.addStaticData("static_data", &test_lua::m_static_data)//注冊靜態變量到lua.addFunction("test", &test_lua::test)//注冊test、方法到lua(addStaticFunction靜態函數注冊也類似).addProperty("name",&test_lua::GetName,&test_lua::SetName)//屬性方法的注冊(addStaticProperty靜態屬性方法也類似).addCFunction("cFunc",&test_lua::cFunc)//注冊返回多個參數給lua的方法.endClass().deriveClass<test_lua_child, test_lua> ("test_lua_child")//子類的注冊.addConstructor<void (*) (std::string)> ()//有參構造函數的注冊.addData("test_child_string", &test_lua_child::m_test_child_string)//注冊變量到lua.endClass().endNamespace();//創建test_lua對象 test_lua test;luabridge::setGlobal(lua_state, &test, "test_lua");//注冊test_lua對象到lua

注:test_lua也可以在lua創建,因為構造函數也注冊到lua,如test.test_lua(),上面的a.lua腳本有子類test_lua_child的創建和調用其父類的屬性方法

4.3、注冊完成后,再返回看上面寫的a.lua腳本就知道每個調用的意義,添加運行Lua腳本 代碼然后執行,代碼如下:

//運行lua腳本luaL_dofile(lua_state, "a.lua"); //關閉Lua lua_close(lua_state); 編譯執行結果為: lua script c++ test string static_data: 12 name: name_property c++ test function 3+4=7 ret1=str1 ret2=str2 call test_lua_child constructor child string:test_string name:child_name_property

4.4、c++調用lua方法,因為lua方法函數參數一樣而且都是一個返回值,為了方便,采用模板形式(以兩個參數為例)第一個參數(lua對象)和第二個參數(方法名)類型固定,后面參數用模板

template<typename R, typename T1, typename T2> R call(lua_State* lua_state,const char* name, T1 arg1, T2 arg2) { //讀取方法名lua_getglobal(lua_state, name); //判斷是不是方法if (lua_isfunction(lua_state, -1)){ //壓入參數 luabridge::Stack<T1>::push(lua_state, arg1); luabridge::Stack<T2>::push(lua_state, arg2); //執行函數(參數為lua對象、參數個數,返回值個數,出錯返回)lua_pcall(lua_state, 2, 1, 0);} //獲取返回值 return luabridge::Stack<R>::get(lua_state, -1); } 在運行lua腳本后面再加上如下調用代碼: //調用lua方法lua_add_functionint ret = call<int>(lua_state,"lua_add_function", 5, 6);//調用lua方法lua_add_str_function std::string value = call<const char*>(lua_state,"lua_add_str_function","5", "6");printf("lua_add_function result:%d\n", ret);printf("lua_add_str_function result:%s\n", value.c_str());

編譯執行結果為:

lua script c++ test string static_data: 12 name: name_property c++ test function 3+4=7 ret1=str1 ret2=str2 call test_lua_child constructor child string:test_string name:child_name_property lua_add_function lua_add_str_function lua_add_function result:11 lua_add_str_function result:56

4.5、最后講一下luaL_dostring

luaL_dostring跟luaL_dofile是一個作用,都是加載并運行lua腳本,只是對象不一樣,看方法名就知道是一個是加載文件,另外一個是加載string,最后運行里面的lua腳本,luaL_dostring在lua嵌入到其他的腳本語言中經常用到,現在沿用上面的例子在lua_close之前加段代碼簡單說明下:

//定義lua腳本,調用test_lua類里的屬性name并打印出來 std::string lua_string = "print(\"run lua string test_lua name:\"..test_lua.name)"; //加載string并運行 luaL_dostring(lua_state, lua_string.c_str()); 編譯運行得到的結果為: run lua string test_lua name:name_property

說到嵌入問題,現在做的向日葵遠程控制軟件的界面用的是xml,這里就涉及到lua嵌入到xml中,由于lua特性,在其他的系統這些xml都可以用,所以以后再也不用擔心加個新界面每個系統還得重新再搞一套,lua嵌入xml中原理就是把lua腳本加入到一個節點中如:

<script><![CDATA[ --lua代碼 print("run lua script")]]></script>

解析xml對應的script節點內容,然后用luaL_dostring去加載運行就可以了。

最后配上現在的向日葵界面圖

向日葵客戶端:

向日葵控制端:

三、小結

希望通過上面的簡單例子可以幫助大家快速上手c++嵌入lua腳本,從上面代碼也可以看出lua和c++很容易互相調用,lua與c++是通過操作虛擬棧來交互的,例如上面調用lua方法,就是c++先把方法放入到棧頂,然后lua從棧頂取值操作,然后把結果又放回到棧頂,c++再從棧頂取值,lua調用c++也類似,就是c++把需要調用的先注冊到lua中,lua就可以調用,想了解更多lua基本語法和原理的可以具體查看lua中的manual.html,LuaBridge的其它用法也可查看LuaBridge的manual.html。

總結

以上是生活随笔為你收集整理的C++和Lua交互教程(基于LuaBridge)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。