一. c++ 調用lua
1. lua文件
str = "I am learning lua!"
tbl = {name = "shun", id = 20200501}
function add(a,b)
return a + b
end
//////////////////////////////////////////////////////////////////////////////////////////
2. main.cpp文件
#include <iostream>
#include <string.h>
using namespace std;
extern "C"
{
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
}
int main()
{
//1.創建Lua狀態
lua_State *L = luaL_newstate();
if (L == NULL)
{
return -1;
}
//2.加載lua文件
int bRet = luaL_loadfile(L,"scripts/testlua.lua");
if(bRet)
{
cout<<"load file error"<<endl;
return -1;
}
//3.運行lua文件
bRet = lua_pcall(L,0,0,0);
if(bRet)
{
cout<<"pcall error"<<endl;
return -1;
}
//4.讀取變量
lua_getglobal(L,"str");
string str = lua_tostring(L,-1);
cout<<"str = "<<str.c_str()<<endl; //str = I am so cool~
//5.讀取table
lua_getglobal(L,"tbl");
lua_getfield(L,-1,"name");
str = lua_tostring(L,-1);
cout<<"tbl:name = "<<str.c_str()<<endl; //tbl:name = shun
//6.讀取函數
lua_getglobal(L, "add"); // 獲取函數,壓入棧中
lua_pushnumber(L, 10); // 壓入第一個參數
lua_pushnumber(L, 20); // 壓入第二個參數
int iRet= lua_pcall(L, 2, 1, 0);// 調用函數,調用完成以後,會將返回值壓入棧中,2表示參數個數,1表示返回結果個數。
if (iRet) // 調用出錯
{
const char *pErrorMsg = lua_tostring(L, -1);
cout << pErrorMsg << endl;
lua_close(L);
return -1;
}
if (lua_isnumber(L, -1)) //取值輸出
{
double fValue = lua_tonumber(L, -1);
cout << "Result is " << fValue << endl;
}
//至此,棧中的情況是:
//=================== 棧頂 ===================
// 索引 類型 值
// 4 int: 30
// 3 string: shun
// 2 table: tbl
// 1 string: I am so cool~
//=================== 棧底 ===================
//7.關閉state
lua_close(L);
return 0;
}
運行結果:
二.lua調用c++
主要兩個方法實現:
方法一:靜態註冊
大概順序就是:在c++中寫一個模塊函數,將函數註冊到lua解釋器中,然後由c++去執行我們的lua文件,然後在lua中調用剛剛註冊的函數。
1. 在目錄下新建一個testlua.lua如下:
avg, sum = average(10, 20, 30, 40, 50)
print("The average is ", avg)
print("The sum is ", sum)
2.新建main.cpp如下:
#include <iostream>
#include <string.h>
using namespace std;
extern "C"
{
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
}
/* 指向Lua解釋器的指針 */
lua_State* L;
static int average(lua_State *L)
{
/* 得到參數個數 */
int n = lua_gettop(L);
double sum = 0;
int i;
/* 循環求參數之和 */
for (i = 1; i <= n; i++)
{
/* 求和 */
sum += lua_tonumber(L, i);
}
/* 壓入平均值 */
lua_pushnumber(L, sum / n);
/* 壓入和 */
lua_pushnumber(L, sum);
/* 返回返回值的個數 */
return 2;
}
int main ( int argc, char *argv[] )
{
//1.創建Lua狀態
lua_State *L = luaL_newstate();
if (L == NULL)
{
return -1;
}
/* 載入Lua基本庫 */
luaL_openlibs(L);
/* 註冊函數 */
lua_register(L, "average", average);
/* 運行腳本 */
bool bRet = luaL_dofile(L, "scripts/testlua.lua");
if(bRet)
{
cout<<"load file error"<<endl;
return -1;
}
/* 清除Lua */
lua_close(L);
/* 暫停 */
system("pause");
return 0;
}
執行一下,得到結果:
方法2:綁定C++對象
1. 建立工程
2. 封裝C++類
1)CMath.H
#ifndef CMATH_H
#define CMATH_H
extern "C"
{
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
}
class CMath
{
public:
CMath();
virtual ~CMath(){}
void setNum(int x);
int getNum();
int Add(int x, int y);
int Sub(int x, int y);
int Mul(int x, int y);
private:
int num;
};
#ifdef __cplusplus
extern "C" {
#endif
int luaopen_cmath(lua_State *L);
#ifdef __cplusplus
}
#endif
#endif // CMATH_H
2) CMath.CPP
#include "cmath.h"
#include "iostream"
using namespace std;
CMath::CMath()
{
}
void CMath::setNum(int x)
{
num = x;
}
int CMath::getNum()
{
return 0;
}
int CMath::Add(int x, int y)
{
cout<<"%p Add="<<this<<",X="<<x<<",Y="<<y<<endl;
return x + y;
};
int CMath::Sub(int x, int y)
{
return x-y;
}
int CMath::Mul(int x, int y)
{
return x*y;
}
////////////////////////////////////////////////////////////////////////////
static int CreateCMath(lua_State* L)
{
// 創建一個元表爲CTest的Table——Lua對象
*(CMath**)lua_newuserdata(L, sizeof(CMath*)) = new CMath();
luaL_getmetatable(L, "CMath");
lua_setmetatable(L, -2);
return 1;
}
static int DestoryCTest(lua_State* L)
{
// 釋放對象
delete *(CMath**)lua_topointer(L, 1);
return 0;
}
static int CallAdd(lua_State* L)
{
int cnt = lua_gettop (L);
// 調用C++類方法的跳板函數。
CMath* pT = *(CMath**)lua_topointer(L, 1);
lua_pushnumber(L, pT->Add(lua_tonumber(L, 2), lua_tonumber(L, 3)));
return 1;
}
static int CallSub(lua_State* L)
{
int cnt = lua_gettop (L);
// 調用C++類方法的跳板函數。
CMath* pT = *(CMath**)lua_topointer(L, 1);
lua_pushnumber(L, pT->Sub(lua_tonumber(L, 2), lua_tonumber(L, 3)));
return 1;
}
static int CallMul(lua_State* L)
{
int cnt = lua_gettop (L);
// 調用C++類方法的跳板函數。
CMath* pT = *(CMath**)lua_topointer(L, 1);
lua_pushnumber(L, pT->Mul(lua_tonumber(L, 2), lua_tonumber(L, 3)));
return 1;
}
static int CallgetNum(lua_State* L)
{
int cnt = lua_gettop (L);
// 調用C++類方法的跳板函數。
CMath* pT = *(CMath**)lua_topointer(L, 1);
lua_pushnumber(L, pT->getNum());
return 1;
}
static int CallsetNum(lua_State* L)
{
int cnt = lua_gettop (L);
// 調用C++類方法的跳板函數。
CMath* pT = *(CMath**)lua_topointer(L, 1);
pT->setNum(lua_tonumber(L, 2));
return 0;
}
static luaL_Reg arraylib_m [] = {
{"Add", CallAdd},
{"Sub", CallSub},
{"Mul", CallMul},
{"setNum", CallsetNum},
{"getNum", CallgetNum}, //print(a)時Lua會調用該元方法。
{NULL, NULL}
};
int luaopen_cmath(lua_State *L){
// 往lua中註冊類
lua_pushcfunction(L, CreateCMath); // 註冊用於創建類的全局函數
lua_setglobal(L, "CMath");
luaL_newmetatable(L, "CMath"); // 創建一個元表
lua_pushvalue(L,-1);
lua_pushstring(L, "__gc"); // 垃圾回收
lua_pushcfunction(L, DestoryCTest);
lua_settable(L, -3); // 公共函數調用的實現就在此啊
lua_pushstring(L, "__index");
lua_pushvalue(L, -2); // 注意這一句,其實是將__index設置成元表自己
lua_settable(L, -3);
// lua_pushstring(L, "Add"); // 放元表中增加一個函數。這樣所有基於該元表的Table就都有Add方法了
// lua_pushcfunction(L, CallAdd);
// lua_settable(L, -3);
//
// lua_pushstring(L, "Sub"); // 放元表中增加一個函數。這樣所有基於該元表的Table就都有Add方法了
// lua_pushcfunction(L, CallSub);
// lua_settable(L, -3);
//
// lua_pushstring(L, "Mul"); // 放元表中增加一個函數。這樣所有基於該元表的Table就都有Add方法了
// lua_pushcfunction(L, CallMul);
// lua_settable(L, -3);
//
// lua_pushstring(L, "setNum"); // 放元表中增加一個函數。這樣所有基於該元表的Table就都有Add方法了
// lua_pushcfunction(L, CallsetNum);
// lua_settable(L, -3);
//
// lua_pushstring(L, "getNum"); // 放元表中增加一個函數。這樣所有基於該元表的Table就都有Add方法了
// lua_pushcfunction(L, CallgetNum);
// lua_settable(L, -3);
// lua_register(L, "getNum", CallgetNum);
// lua_pop(L,1);
luaL_setfuncs(L,arraylib_m,0);
return 0;
}
3) main.cpp測試函數
#include <iostream>
#include <string.h>
#include <cmath.h>
using namespace std;
int main ( )
{
lua_State *L = luaL_newstate();
if (L == nullptr)
{
return -1;
}
luaL_openlibs(L);
luaopen_cmath(L); //打開封裝的C++lib庫
int bRet = luaL_dofile(L, "scripts/testlua.lua");
if (bRet)
{
cout << "call testlua.lua file failed" << endl;
return -1;
}
lua_close(L);
// waiting for console
cin.get();
return 0;
}
4) testlua.lua調用C++方法
--第四步:在lua中調用 cpp_add,cpp_sub直接操作
--testlua. lua代碼
c = CMath()
d = CMath()
print("c.Add(1, 2) ==> " .. c:Add(1, 2));
print("d.Sub(104, 5) ==> " .. d:Sub(104, 5));
print("d.Mul(104, 5) ==> " .. d:Mul(104, 5));
--c::setNum(23);
print(c:getNum());
--print("d.Add(4, 5) ==> " .. d:Add(4, 5));
5)運行結果
三.總結
lua和c++是通過一個虛擬棧來交互的。
c++調用lua實際上是:由c++先把數據放入棧中,由lua去棧中取數據,然後返回數據對應的值到棧頂,再由棧頂返回c++。
lua調c++也一樣:先編寫自己的c模塊,然後註冊函數到lua解釋器中,然後由lua去調用這個模塊的函數。