C++ 和 Lua 交互學習
Lua簡介及安裝
Lua的優點:
- 最快的腳本語言
- 可以編譯調試
- 與C/C++結合容易
- Lua是對性能有要求的必備語言
Lua的應用:
- 遊戲的任務腳本,後端服務器
- AlphaGo: C++ + lua實現
- 視頻服務器、入侵檢測腳本、防火牆腳本
Lua的官網: http://www.lua.org/versions.html
- 5.1 較快
- 5.3 性能有些下降
Lua的安裝
C++ 調用 lua之前需要先安裝lua,可以下載lua的源碼進行編譯安裝,在CentOS平臺下,還可以直接使用yum安裝,CentOS默認使用lua的版本是5.1的版本,如:
yum install lua lua-devel
Lua 的基本概念
Lua的基本數據類型:
- nil:表示沒有數據,當希望釋放數據時,直接將nil賦值給該變量即可
- boolean:在lua中除了false和nil爲假,其他都爲真,true|false
- numbers類型:
- lua中沒有整數,都是浮點數運算,對應C中的double;
- 新版本的lua是基於64位的整型,5.1暫不支持
- 可以tonumber轉換格式
- string類型:
- tostring轉換格式
- [[]]多行字符串賦值
- 與C一樣的轉義
- 通過..實現字符串的拼接,且可以直接拼接整型,注意不能拼接nil的變量
- string.len(str), 獲取字符串長度
- string.sub(str,3,5),獲取子字符串
- local b,e = string.find(),查找,支持正則
- string.gsub(),替換,不改變原值,返回替換後的值,支持正則
- lua的下標是從1開始的,和matlab相同
Lua和C++的交互
調用C++中的函數, 通過堆棧交互
包含頭文件
extern "C"
{
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}
編譯
g++ -o XX XX.cpp -llua -ldl
第一個例子
C++代碼
#include <iostream>
using namespace std;
extern "C"
{
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}
int main()
{
lua_State *L = lua_open();
luaopen_base(L);
luaopen_string(L);
luaopen_table(L);
// 加載 lua 文件
if ( luaL_loadfile(L, "main.lua") )
{
const char* error = lua_tostring(L, -1);
cout << "lua load error: "<< error << endl;
return -1;
}
// 執行 lua 文件
if ( lua_pcall(L, 0, 0, 0) )
{
const char* error = lua_tostring(L, -1);
cout << "lua call error: "<< error << endl;
return -1;
}
getchar();
return 0;
}
lua代碼
print("hello word")
第二個列子
C++ code
#include <iostream>
using namespace std;
extern "C"
{
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}
// 開放函數給lua調用,並獲取 Lua 傳遞的三個參數,普通參數
int CTest(lua_State* L)
{
cout << "enter in CTest" << endl;
size_t len;
const char* name = lua_tolstring(L, 1, &len);
cout << "Lua name: " << name << endl;
int age = lua_tonumber(L, 2);
cout << "Lua age: " << age << endl;
bool bIs = lua_toboolean(L, 3);
cout << "Lua bool: " << bIs << endl;
return 0;
}
// 開放函數給lua調用,並獲取 Lua 傳遞的表參數,按索引獲取表參數
int CTestArray(lua_State* L)
{
cout << "In CTestArray" << endl;
int arrLen = luaL_getn(L,1); // 獲取表的長度
cout << "Table size: " << arrLen << endl;
for (int i = 1; i <= arrLen; i++)
{
lua_pushnumber(L, i); // 2
lua_gettable(L,1); // pop index and push table[i]
size_t iSize = 0;
cout << lua_tolstring(L, -1, &iSize) << endl;
lua_pop(L, 1);
}
return 0;
}
// 開放函數給lua調用,並獲取 Lua 傳遞的表參數,按鍵值獲取表參數
int CTestKeyVal(lua_State* L)
{
cout << "In CTestKeyVal" << endl;
lua_pushnil(L);
while(lua_next(L,1) != 0)
{
cout << "key=" << lua_tostring(L,2) << ", ";
cout << "value=" << lua_tostring(L,-1) << endl;
lua_pop(L,1);
}
return 0;
}
// 開放函數給lua調用,並判斷獲取的參數是否是希望的類型
int CTestKeyVal_type(lua_State* L)
{
// method1: type check
luaL_checktype(L, 1, LUA_TTABLE);
// method2: type check
if (lua_type(L,2) != LUA_TNUMBER)
{
cout << "para 2 is not a number" << endl;
}
cout << "In CTestKeyVal" << endl;
lua_getfield(L,1, "name");
cout << "name: " <<lua_tostring(L,-1) <<endl;
return 0;
}
// 開放函數給lua調用,C++ 返回一個普通的字符串
int CTestRetOne(lua_State* L)
{
lua_pushstring(L, "return a string value");
return 1;
}
// 開放函數給lua調用,C++ 返回一個表
int CTestRetTable(lua_State* L)
{
lua_newtable(L); // create new table
lua_pushstring(L, "name"); // push key
lua_pushstring(L, "xiaominmin");// pusn value
lua_settable(L, -3);// write key and value into table
lua_pushstring(L, "age");
lua_pushnumber(L, 29);
lua_settable(L, -3);
return 1;
}
int main()
{
lua_State *L = lua_open();
luaopen_base(L);
luaopen_string(L);
luaopen_table(L);
// 註冊開發的函數給lua
lua_register(L, "CTest", CTest);
lua_register(L, "CTestArray", CTestArray);
lua_register(L, "CTestKeyVal", CTestKeyVal);
lua_register(L, "CTestKeyVal_type", CTestKeyVal_type);
lua_register(L, "CTestRetOne", CTestRetOne);
lua_register(L, "CTestRetTable", CTestRetTable);
if ( luaL_loadfile(L, "main.lua") )
{
const char* error = lua_tostring(L, -1);
cout << "lua load error: "<< error << endl;
return -1;
}
if ( lua_pcall(L, 0, 0, 0) )
{
const char* error = lua_tostring(L, -1);
cout << "lua call error: "<< error << endl;
return -1;
}
getchar();
return 0;
}
lua code
-- 調用 CTest,並傳遞三個普通參數
CTest("Lua string",123, true)
-- 調用CTestArray,並傳遞帶索引的表
local arr = {"A001","A002","A003", "A004"}
CTestArray(arr)
-- 調用 CTestKey,並傳遞鍵值表
local arr = {name="xiaoming", age="32",id="007"}
local size = "s108"
CTestKeyVal(arr)
-- 調用 CTestKey_type,並傳遞鍵值表,判讀參數類型是否是期望的類型
local arr = {name="xiaoming", age="32",id="007"}
local size = "s108"
CTestKeyVal_type(arr, size)
-- 調用 CTestRetOne,並打印C++返回的值
local ret = CTestRetOne()
print ("ret = "..ret)
-- 調用 CTestRetTable,並打印C++的表
local ret = CTestRetTable()
print ("name = "..ret["name"])
print ("age = "..ret["age"])
第三個例子
C++ code
#include <iostream>
using namespace std;
extern "C"
{
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}
int main()
{
lua_State *L = lua_open();
// 打開需要用到的lua的庫
luaopen_base(L);
luaopen_string(L);
luaopen_table(L);
/* lua腳本啓動之前,給lua腳本設置全局變量 */
// 設置lua的全局變量,hello = test (key = value)
lua_pushstring(L, "hello");
lua_setglobal(L,"test");
// 向 lua 中傳遞一個表,同例子2中的返回一個表給lua
lua_newtable(L); // create a table
lua_pushstring(L, "name"); // key
lua_pushstring(L, "xiaoming"); // value
lua_settable(L, -3);
lua_pushstring(L, "age"); // key
lua_pushnumber(L, 20); // value
lua_settable(L, -3);
lua_setglobal(L, "person"); // write value to table
if ( luaL_loadfile(L, "main.lua") )
{
const char* error = lua_tostring(L, -1);
cout << "lua load error: "<< error << endl;
return -1;
}
if ( lua_pcall(L, 0, 0, 0) )
{
const char* error = lua_tostring(L, -1);
cout << "lua call error: "<< error << endl;
return -1;
}
// C++ 獲取lua中的普通全局變量
lua_getglobal(L, "width");
int width = lua_tonumber(L, -1);
lua_pop(L, 1); // 注意要清lua堆棧
cout << "width: " << width << endl;
// C++ 獲取lua中的表全局變量
lua_getglobal(L, "conf");
lua_getfield(L, -1, "titlename");
cout << "titlename: " << lua_tostring(L,-1) << endl;
lua_pop(L,1);
lua_getfield(L, -1, "height");
cout << "height: " << lua_tonumber(L, -1) << endl;
lua_pop(L, 1);
// C++ 調用 lua中的名爲 event的函數,無參數無返回值
cout<< "stack top is " << lua_gettop(L) << endl;
lua_getglobal(L, "event");
if ( lua_pcall(L, 0, 0, 0) != 0)// 無參數,無返回值,無回調函數
{
cout << "call event failed " << lua_tostring(L, -1)<< endl;
lua_pop(L, 1);
}
cout<< "stack top is " << lua_gettop(L) << endl;
// C++ 調用 lua中的名爲 ferror和event2 的函數,有參數有返回值
cout<< "stack top is " << lua_gettop(L) << endl;
int errfun = lua_gettop(L);
lua_getglobal(L, "ferror");
errfun++;
lua_getglobal(L, "event2");
lua_pushstring(L, "key");
if ( lua_pcall(L, 1, 1, errfun) != 0)// 一個參數,一個返回值,回調函數errfun
{
cout << "call event failed " << lua_tostring(L, -1)<< endl;
lua_pop(L, 1);
}
else
{
cout << "Lua return: " << lua_tostring(L, -1) << endl;
lua_pop(L, 1);
}
lua_pop(L, 1);
cout<< "stack top is " << lua_gettop(L) << endl;
// C++ 調用 lua中的名爲 ferror和event3 的函數,有表參數和表返回值
cout<< "stack top is " << lua_gettop(L) << endl;
int errfun1 = lua_gettop(L);
lua_getglobal(L, "ferror");
errfun1++;
lua_getglobal(L, "event3");
lua_pushstring(L, "key");
lua_newtable(L);
lua_pushstring(L,"name");
lua_pushstring(L, "xiaomingming");
lua_settable(L, -3);
if ( lua_pcall(L, 2, 1, errfun) != 0) // 兩個參數,一個返回值,回調函數errfun
{
cout << "call event failed " << lua_tostring(L, -1)<< endl;
lua_pop(L, 1);
}
else
{
//cout << "Lua return: " << lua_tostring(L, -1) << endl;
lua_getfield(L, -1, "id");
cout << "Lua return id: " << lua_tonumber(L, -1) << endl;
lua_pop(L,1);
lua_getfield(L, -1, "age");
cout << "lua return age: " << lua_tonumber(L, -1) << endl;
lua_pop(L, 1);
lua_pop(L, 1);
}
lua_pop(L, 1);
cout<< "stack top is " << lua_gettop(L) << endl;
lua_close(L);
return 0;
}
lua code
-- Lua的全局變量,供C++使用
width=1920
conf =
{
titlename = "first lua",
height = 1080
}
-- 打印C++設置的全局變量,普通變量
print("C++ test: ".. test)
-- 打印C++設置的全局變量,表
for k,v in pairs(person) do
print(k.."=>"..v)
end
-- C++ 調用 lua函數並傳遞普通參數,lua函數有返回值
function ferror(e)
print("lua error: "..e)
return "lua change error"
end
-- C++ 調用 lua函數,無參數,lua函數無返回值
function event()
print("C++ call lua function.")
end
-- C++ 調用 lua函數並傳遞普通參數,lua函數有返回值
function event2(e)
print("C++ call lua function event 1.")
print(e)
return "Lua renturn a string"
end
-- C++ 調用 lua函數並傳遞表參數,lua函數返回表參數
function event3(e, obj)
print("C++ call lua function event 1.")
print(e)
print (obj.name)
local re = {id=123, age=29}
return re
end