在 C++ 中调用 Lua 程序

概述

在阅读了两篇关于 C/C++ 如何调用 Lua 脚本的文章后,对整个调用过程进行一个总结,并输出示例。

环境

Ubuntu 14.04, gcc version 4.9.4 (GCC), Lua 5.2.4

Lua 安装
下载 Lua 5.2.4
解压后,进入 lua-5.2.4 目录

1
2
3
./make linux
./make install check
./make install

流程

  1. 创建一个 Lua state 变量
  2. 加载 Lua 库
  3. 加载 Lua 脚本文件
  4. 启动脚本运行以创建脚本的全局变量
  5. 将所有参数传递到堆栈上的Lua脚本
  6. 运行加载的 Lua 脚本
  7. 从 Lua 脚本中获取返回值
  8. 关闭 Lua state 变量

测试

了解了怎样去调用 Lua 文件的流程之后,我们可以写一些代码进行测试。

C++ 调用 Lua 文件

首先,尝试在 C++ 程序中直接运行 Lua 脚本。对应的 run_lua_file.cpp 代码为:

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
30
31
32
33
34
35
36
37
38
#include <iostream>
#include "lua.hpp"
using namespace std;
void print_error(lua_State* state) {
const char* message = lua_tostring(state, -1);
puts(message);
lua_pop(state, 1);
}
void execute(const char* filename) {
lua_State* state = luaL_newstate();
luaL_openlibs(state);
int result;
result = luaL_loadfile(state, filename);
if (result != LUA_OK) {
print_error(state);
return;
}
result = lua_pcall(state, 0, LUA_MULTRET, 0);
if (result != LUA_OK) {
print_error(state);
return;
}
}
int main(int argc, char** argv) {
if (argc <= 1) {
cout << "Usage: runlua file(s)" << endl;
cout << "Loads and executes Lua programs." << endl;
return 1;
}
for (int n=1; n<argc; ++n) {
execute(argv[n]);
}
return 0;
}

对应的 helloworld.lua 代码为:

1
io.write(string.format("Hello world from %s \n", _VERSION))

运行

1
./run_lua_file ../script/helloworld.lua

程序执行的结果为:

1
Hello world from Lua 5.2

这正是 helloworld.lua 打印出的一句话。由此可见,从 C++ 程序中成功运行了 Lua 脚本。

C++ 调用 Lua 函数

其实,C++ 程序不但可以直接运行 Lua 脚本,而且可以调用其中的方法。示例如下:

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include <iostream>
#include "lua.hpp"
using namespace std;
void print_error(lua_State* state) {
const char* message = lua_tostring(state, -1);
cout << message << endl;
lua_pop(state, 1);
}
void execute(const char* filename) {
// Create a Lua state variable
lua_State* state = luaL_newstate();
// Load Lua libraries
luaL_openlibs(state);
// Load but don't run the Lua script
int result;
result = luaL_loadfile(state, filename);
// Error out if file can't be read
if (result != LUA_OK) {
print_error(state);
return;
}
// Run the loaded Lua script
result = lua_pcall(state, 0, 0, 0);
// Error out if Lua file has an error
if (result != LUA_OK) {
print_error(state);
return;
}
int a = 1;
int b = 2;
cout << "In C++, calling Lua function add(" << a <<"," << b << ")" << endl;
lua_getglobal(state, "add");
// Pass all arguments to the Lua script on the stack
lua_pushnumber(state, a);
lua_pushnumber(state, b);
result = lua_pcall(state, 2, 1, 0);
if (result != LUA_OK) {
print_error(state);
return;
}
cout << "Back in C++ again." << endl;
// Retrieve the return from the Lua script
int number = lua_tonumber(state, -1);
cout << "add(" << a << "," << b << ") = " << number << endl;
cout << "In C++, calling Lua function isPositive(" << number << ")" << endl;
lua_getglobal(state, "isPositive");
// Pass all arguments to the Lua script on the stack
lua_pushnumber(state, number);
// Run the loaded Lua script
result = lua_pcall(state, 1, 1, 0);
if (result != LUA_OK) {
print_error(state);
return;
}
cout << "Back in C++ again." << endl;
// Retrieve the return from the Lua script
bool flag = lua_toboolean(state, -1);
cout << "isPositive(" << number << ") = " << flag << endl;
// Close the Lua state variable
lua_close(state);
}
int main(int argc, char** argv) {
if (argc <= 1) {
cout << "Usage: runlua file(s)" << endl;
cout << "Loads and executes Lua programs." << endl;
return 1;
}
for (int n=1; n<argc; ++n) {
execute(argv[n]);
}
return 0;
}

callfunc.lua 代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
function add(a, b)
c = a + b
return c
end
function isPositive(a)
if(a > 0)
then
return true
else
return false
end
end

执行

1
./call_lua_func ../script/callfunc.lua

后,打印结果如下:

1
2
3
4
5
6
In C++, calling Lua function add(1,2)
Back in C++ again.
add(1,2) = 3
In C++, calling Lua function isPositive(3)
Back in C++ again.
isPositive(3) = 1

Lua 调用 C++ 函数

从上述两个示例可以看到,C++ 程序可以调用 Lua 程序。我们还可以在 Lua 程序中调用 C++ 程序中的函数。直接看代码:

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <iostream>
#include "lua.hpp"
using namespace std;
int callback(lua_State* state) {
int args = lua_gettop(state);
cout << "callback() was called with arguments: " << args << endl;
for (int n=1; n<=args; ++n) {
cout << "argument " << n << ": " << lua_tostring(state, n) << endl;
}
lua_pushnumber(state, 123);
return 1;
}
void print_error(lua_State* state) {
const char* message = lua_tostring(state, -1);
cout << message << endl;
lua_pop(state, 1);
}
void execute(const char* filename) {
lua_State* state = luaL_newstate();
luaL_openlibs(state);
lua_register(state, "callback", callback);
int result;
result = luaL_loadfile(state, filename);
if (result != LUA_OK) {
print_error(state);
return;
}
result = lua_pcall(state, 0, LUA_MULTRET, 0);
if (result != LUA_OK) {
print_error(state);
return;
}
lua_close(state);
}
int main(int argc, char** argv) {
if (argc <= 1) {
cout << "Usage: runlua file(s)" << endl;
cout << "Loads and executes Lua programs." << endl;
return 1;
}
for (int n=1; n<argc; ++n) {
execute(argv[n]);
}
return 0;
}

callback.lua 的代码为:

1
2
3
io.write("Calling callback() ...\n")
local value = callback("First", "Second", 3)
io.write(string.format("callback() returned: %s \n", tostring(value)))

执行

1
./lua_callback ../script/callback.lua

后,打印结果如下:

1
2
3
4
5
6
Calling callback() ...
callback() was called with arguments: 3
argument 1: First
argument 2: Second
argument 3: 3
callback() returned: 123

该程序的执行流程为:lua_callback.cpp main -> lua_callback.cpp execute -> callback.lua callback -> lua_callback.cpp callback
在 .cpp 中调用 .lua 文件,接着.lua 文件里调用了 .cpp 文件中的 callback 函数,最终的打印结果便是由 callback 函数输出的。

上面的三个示例都是 C++ 与 Lua 间的调用,将 C++ 换成 C 语言来运行 Lua,同样也是可行的,这里不继续贴代码了。

参考

  1. Using Lua with C++ — A short tutorial
  2. Calling Lua From a C Program
  3. cpp_call_lua_demo