C++ 与 lua 联合编程
Alex 9/2/2024 luaC++
# 环境部署
有两种方案
# 全局安装 lua 解释器
brew install lua
1
使用 pkg-config 在 cmake 中载入 lua
find_package(PkgConfig REQUIRED)
pkg_check_modules(LUA REQUIRED lua)
target_link_libraries(main PRIVATE ${LUA_LIBRARIES})
target_link_directories(main PRIVATE ${LUA_LIBRARY_DIRS})
target_include_directories(main PRIVATE ${LUA_INCLUDE_DIRS})
1
2
3
4
5
2
3
4
5
# vcpkg
{
"name": "cxx-lua",
"version-string": "1.0.0",
"builtin-baseline": "e590c2b30c08caf1dd8d612ec602a003f9784b7d",
"dependencies": [
{
"name": "lua",
"version>=": "5.4.6"
}
]
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
在 cmake 中载入 lua
find_package(Lua REQUIRED)
target_include_directories(main PRIVATE ${LUA_INCLUDE_DIR})
target_link_libraries(main PRIVATE ${LUA_LIBRARIES})
1
2
3
2
3
vcpkg 也支持全局模式,与 brew 用法区别不大不再赘述
# Hello World
为了避免函数名冲突,要使用 extern "C" 包裹lua头文件,声明这些是C的函数。 lua 是脚本语言,修改 lua 文件之后无需重新编译 C++,重新执行程序即可
main.lua
print "Hello World"
1
main.cpp
#include <iostream>
// 避免函数签名冲突
extern "C" {
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
}
int main() {
lua_State* L = luaL_newstate(); // 5.0 之后使用 luaL_newstate 替代 lua_open
if (!L) {
std::cerr << "Cannot create state: Not enough memory" << std::endl;
return 1;
}
luaL_openlibs(L);
if (luaL_loadfile(L, "main.lua")) {
std::cerr << "lua load error: " << lua_tostring(L, -1) << std::endl;
}
if (lua_pcall(L, 0, 0, 0)) {
std::cerr << "lua call error: " << lua_tostring(L, -1) << std::endl;
}
lua_close(L);
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
执行结果
Hello World
1
# 变量
全局变量,全局可用
a = 100
1
本地变量,从当前作用域离开之后就会被垃圾回收,类似 RAII
local a = 100
1
# 数据类型
四个基础数据类型
- Nil
- Booleans
- Numbers
- Strings
Booleans 和 Nil 不赘述
# 识别变量类型
i = 100
s = "str"
print(type(i), type(s))
1
2
3
2
3
运行结果
number string
1
# Numbers
在 lua 5.1 之后 int 类型基于双精度类型存储
a = 100
1
# Strings
a = "string"
1
多行字符串使用 [[]] 定义
s = [[
<html>
<h1>Hello World
</h1>
</html>
]]
print(s)
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
拼接字符串使用 .. 运算符,同时也可以拼接数字类型
a = "lua".."str"..123
1
一部分标准库
- 获取长度
string.len(a)
- 截取
string.sub(a, 2, 3)
- 查找
local b, c = string.find(a, "HEAD or regex")
- 替换
string.gsub(a, "str or regex", "new str")
# 类型转换
i = 100
s = "1"
print(type(i), type(s))
print(type(tostring(i)), type(tonumber(s)))
1
2
3
4
5
2
3
4
5
运行结果
number string
string number
1
2
2
# 数组
# 表
# 在 lua 中引用其他 lua 文件
dofile("do.lua")
1
示例程序
main.lua
a = 100
local b = 1
print("print a in main.lua", a)
print("print b in main.lua", b)
dofile("sub.lua")
1
2
3
4
5
6
7
2
3
4
5
6
7
sub.lua
print("print a in sub.lua", a)
print("print b in sub.lua", b)
1
2
2
执行结果
全局变量可以跨文件读取,但局部变量不能
print a in main.lua 100
print b in main.lua 1
print a in sub.lua 100
print b in sub.lua nil
1
2
3
4
2
3
4
# 流程控制
# 分支
分支采用 if then end 结构,elseif 也要加 then
a = 2;
if (a == 1 or a == 2) then
print(12, a)
elseif (a == 3) then
print(3, a)
else
print(0, a)
end
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 循环
while
a = 0;
while (a < 5) do
print(a)
a = a + 1
end
1
2
3
4
5
6
2
3
4
5
6
运行结果
0
1
2
3
4
1
2
3
4
5
2
3
4
5
# repeat
repeat .. until 类似 do .. while
a = 0;
repeat
print(a)
a = a + 1
until a > 5
1
2
3
4
5
6
2
3
4
5
6
# for
for
1