C++與Lua互動1: C++呼叫lua
阿新 • • 發佈:2018-12-15
lua作為一門動態語言,可用來當做配置檔案和實現經常變化的業務功能,很方便的實現熱更新。同時lua作為一門膠水語言,配合強大的C++作邏輯支撐,程式效能高、開發效率快,猶如珠簾合璧,所向無敵。C++與lua的互動主要通過lua的虛擬棧實現,本文不打算深入講解其中原理,只是簡單記錄下C++與lua的呼叫關係。
環境搭建
mac、linux系統: $ wget http://www.lua.org/ftp/lua-5.2.3.tar.gz $ tar zxf lua-5.2.3.tar.gz $ cd lua-5.2.3 $ make posix $ make posix install
windows系統:略
1.C++呼叫lua
假如當前資料夾為demo1。先建立一個lua指令碼, 路徑為:demo1/scripts/test.lua。指令碼內容如下:
-- 全域性變數 id = 666 title = "this is a test" array = {r = 2,g = 3,b = 4} array_1d = {2,5,26,8} array_2d = {{2,5},{15,18},{25,26,28},{0,5,4}} -- 無參函式 function ruler_func() print("[lua]: this is some thing need to tell you!!!"); end -- 有參函式 function add_func(a,b) print("[lua]: a("..a..") + b("..b..") ="..a+b.."!"); return a+b; end
在當前資料夾建立C++檔案demo1/demo.cpp,用來測試呼叫lua指令碼。檔案內容如下:
/* * demo.cpp * demo * * Created by Jevstein on 2018/10/16 11:30. * Copyright @ 2018year Jevstein. All rights reserved. * */ #include <iostream> #include <string> using namespace std; //0.包含lua標頭檔案 extern "C" { #include <lua.h> #include <lauxlib.h> #include <lualib.h> } void call_lua_test() { //1.建立lua環境 lua_State *L = luaL_newstate(); //lua_open() if (L == NULL) { std::cout << "[C++]: Failed to create Lua State!" << std::endl; return; } //2.載入庫 luaL_openlibs(L);//載入終端輸出列印資訊庫,屆時可看到lua的print資訊 //3.載入lua指令碼 const std::string script = "./scripts/test.lua"; int ret = luaL_dofile(L, script.c_str()); if (ret != 0) { std::cout << "[C++]: Failed to load lua !" << std::endl; return; } //4.呼叫指令碼內容: 變數、函式等 // 為簡化程式碼,以下可以對其封裝,如: // bool load_file(string str); //載入檔案 // string load_string(string str); //讀取string變數 // int load_integer(string str); //讀取int變數 // double load_double(string str); //讀取double變數 // bool load_boolean(string str); //讀取bool變數 // bool load_map(const char* name, const int number, string str[], double array_list[], int type = 0); //讀取map // bool load_array(const char* name, int*& array); //讀取array {//4.1.無參函式 std::cout << "[C++]: 1.Get variable !" << std::endl; lua_getglobal(L, "id");//變數名稱 if (lua_isnumber(L, -1)) { int id = 0; std::cout << "[C++]: The result is id=" << (int)lua_tointeger(L, -1) << endl; } } {//4.2.無參函式 std::cout << "[C++]: 2.Call ruler_func() !" << std::endl; lua_getglobal(L, "ruler_func"); //指令碼函式名: ruler_func lua_pcall(L, 0, 0, 0); //用保護模式呼叫lua函式:入參個數為0、出參個數為0、無自定義錯誤處理 } {//4.3.有參函式 int number1 = 100; int number2 = 200; printf("[C++]: 3.Call add_func(%d, %d)!\n", number1, number2); lua_getglobal(L, "add_func"); //指令碼函式名: add_func lua_pushnumber(L, number1); //引數1入參: 100 lua_pushnumber(L, number2); //引數2入參: 200 lua_pcall(L, 2, 1, 0); //函式有兩個入參,一個出參,所以函式形式為add(a,b) //獲得返回值: 單回值情況下呼叫完成後lua會把結果放到棧頂,多返回值時,按照規則存放 if (lua_isnumber(L, -1) != 0) { std::cout << "[C++]: The result is :" << lua_tonumber(L, -1) << endl; } } //5.銷燬lua環境 lua_close(L); } int main() { std::cout << "--------- sample: C++ call Lua --------- " << std::endl; call_lua_test(); std::cout << "--------- the end --------- " << std::endl; return 0; }
linux下,使用g++編譯: $ g++ -o demo *.cpp -llua -ldl
執行demo,結果如下:
2.lua呼叫C++
lua呼叫C/C++,需要將C/C++編譯成動態庫。假如當前資料夾為demo2。先建立C++檔案, 路徑為:demo2/lcpp/MyLuaMath.h和demo2/lcpp/MyLuaMath.cpp。檔案內容如下: C++標頭檔案:
/* * MyLuaMath.h * MyLuaMath * * Created by Jevstein on 2018/10/17 17:36. * Copyright @ 2018year Jevstein. All rights reserved. * */ #ifdef __cplusplus # define EXTERN_C extern "C" #else//!__cplusplus # define EXTERN_C #endif//__cplusplus #ifdef WIN32 # ifdef MY_EXPORTS # define MY_REPORT_API EXTERN_C _declspec(dllexport) # else # define MY_REPORT_API EXTERN_C _declspec(dllimport) # endif # define CALLMODE __cdecl //__stdcall #else//!WIN32 # define MY_REPORT_API EXTERN_C # define CALLMODE #endif//WIN32 /************************************************************************/ /* 函式宣告 */ /************************************************************************/ int add_func(lua_State* L); int sub_func(lua_State* L); int mul_func(lua_State* L); int div_func(lua_State* L);
C++實現檔案:
/*
* MyLuaMath.cpp
* MyLuaMath
*
* Created by Jevstein on 2018/10/17 17:45.
* Copyright @ 2018year Jevstein. All rights reserved.
*
*/
#include <iostream>
extern "C"
{
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
}
#include "MyLuaMath.h"
#define MY_EXPORTS
/************************************************************************/
/* 1.函式實現 */
/************************************************************************/
int add_func(lua_State* L)
{
//if (!lua_isnumber(state, 1))
// printf("type invalid!");
int a = lua_tonumber(L, 1);
int b = lua_tonumber(L, 2);
int ret = a + b;
lua_pushnumber(L, ret);
return 1;//1個返回值
}
int sub_func(lua_State* L)
{
int a = lua_tonumber(L, 1);
int b = lua_tonumber(L, 2);
int ret = a - b;
lua_pushnumber(L, ret);
return 1;
}
int mul_func(lua_State* L)
{
int a = lua_tonumber(L, 1);
int b = lua_tonumber(L, 2);
int ret = a * b;
lua_pushnumber(L, ret);
return 1;
}
int div_func(lua_State* L)
{
int a = lua_tonumber(L, 1);
int b = lua_tonumber(L, 2);
int ret = (b == 0) ? 0 : a / b;
lua_pushnumber(L, ret);
return 1;
}
/************************************************************************/
/* 2.函式陣列 */
/************************************************************************/
static const struct luaL_Reg funcs__[] =
{
{ "add", add_func },
{ "sub", sub_func },
{ "mul", mul_func },
{ "div", div_func },
{ NULL, NULL }
};
/************************************************************************/
/* 3.匯出介面 */
/* [注]函式名luaopen_libmyluamath中的'libmyluamath'必須為庫函式名,如:*/
/* libmyluamath.so */
/************************************************************************/
MY_REPORT_API int CALLMODE luaopen_libmyluamath(lua_State* L)
{
//lua5.1之前版本使用如下:
//luaL_openlib(L, "MyMath", funcs__, 0); //或luaL_register(L, "mymath", funcs__);
//lua5.2以上版本使用如下:
lua_getglobal(L, "MyMath");
if (lua_isnil(L, -1))
{
lua_pop(L, 1);
lua_newtable(L);
}
luaL_setfuncs(L, funcs__, 0);
lua_setglobal(L, "MyMath");
return 0;
}
然後建立lua指令碼,測試C++的功能。檔案路徑:demo2/demo.lua,內容如下:
package.cpath = package.cpath .. ";./lcpp/?.so"
require("libmyluamath")
local a = 200
local b = 100
local ret = MyMath.add(a, b)
print("a + b = " ..a .. " + " .. b .. " = "..ret)
local ret = MyMath.sub(a, b)
print("a - b = " ..a .. " - " .. b .. " = "..ret)
local ret = MyMath.mul(a, b)
print("a * b = " ..a .. " * " .. b .. " = "..ret)
local ret = MyMath.div(a, b)
print("a / b = " ..a .. " / " .. b .. " = "..ret)
linux下用g++編譯C++動態庫: $ g++ -fPIC -shared -o libmyluamath.so *.cpp -llua -ldl 再用執行指令碼: $ lua demo.lua
結果如下: