标签:接下来 一个 code exec info ace 比较 clu VID
马上要开始实习了,在实习中会用到skynet这个框架,这个框架主要就是由 C 以及 Lua 进行实现的,于是就学习了一下 Lua 的基本语法以及如何使用进行 C++ 和 Lua 的混合编程。
本篇论文主要记录一下如何在C++代码中调用Lua的代码,以及如何让程序跑起来,因为之前看到很多博客虽然都说明了代码怎么写,但始终对于如何让代码跑起来不是很清楚。经过反复折腾总算是能运行起来了,当然作为一个初学者来说,我的方法可能比较麻烦,不应当作为范例,以后也可能会纠正,同时有些地方可能会存在错误,也希望大家能指正我。
主要用到的一些工具:
Lua 和 cmake 先学好预备知识,Lua 我是直接看菜鸟的,cmake 是在B站找了个视频看了下,基本看得快各一天就能看完。链接里是我参考的学习资料。
我理解的Lua一方面是一个脚本语言,另一方面也可以当作C/C++的库来使用,有了这个库之后就可以在 C++ 的代码中直接运行 Lua 文件。
首先第一步肯定就是下载 Lua 了,网上有很多教程,然后记住 Lua 的源代码的地址,后面会用到。
然后就可以开始写 Lua 的代码了,首先在项目目录中创建一个 lua_code
目录用来存放 Lua 代码,比如写一个 add.lua
文件,代码如下:
print("C++ call Lua!!")
str = "I am a student."
tbl = {name="Gong", id=20210405}
function add(x, y)
return x + y
end
代码中首先进行了 print
输出,然后创建了两个全局变量和一个函数,等下会说明如何在 C++ 代码中对这三者进行访问。
在项目目录中创建一个 src
进行存放 C++ 的源代码,然后在该目录下创建 main.cpp
。首先在头部添加头文件:
#include <iostream>
#include <string>
extern "C" {
#include "lua.h"
#include "lauxlib.h"
#include "liblua.h"
}
using namespace std;
这里用 extern "C"
的原因是 Lua 的库是用 C 实现的,而 C 和 C++ 的编译还是存在着一些细微的差别的,这里主要就是告诉编译器这些文件是用C编译的。
接下来就是如何在 main 函数中调用 Lua 定义的变量及函数。
C++ 和 Lua 的交互主要是靠虚拟栈来实现的。首先 C++ 中会创建出这个虚拟栈L,然后再打开 Lua 的某个代码文件和这个栈进行绑定,虚拟栈是由 C++ 文件创建出来的,又和某个 Lua 代码文件进行了绑定,这就将 C++ 和 Lua 联系起来了。然后只要在 C++ 中将数据入栈,在 Lua 中将数据出栈,或者 Lua 中将数据入栈,在 C++ 中将数据出栈,这样就完成二者的数据交互。
首先是创建这个虚拟栈L(luaL_newstate()
),以及打开 Lua 的标准库(luaL_openlibs(L)
),代码如下:
lua_State *L = new luaL_newstate();
luaL_openlibs(L);
主要用到 luaL_loadfile(L, lua_path)
进行绑定,以及 luaL_pcall(L, 0, 0, 0)
进行执行(执行之后才能知道这个文件中有哪些变量和函数,这里先不说明后三个参数,只要记住都输入0即可)。二者都是如果失败就返回非0值。
int bRet;
if (bRet = luaL_loadfile(L, "../lua_code/add.lua")) {
cout << "load lua file error" << endl;
return 1;
}
if (bRet = luaL_pcall(L, 0, 0, 0)) {
cout << "pcall error" << endl;
return 1;
}
当然绑定和执行一般都是要一块执行的,也有一个将二者合二为一的函数 lua_dofile(L, lua_path)
:
if (bRet = luaL_dofile(L, "../lua_code/add.lua")) {
cout << "load and run lua file error" << endl;
return 1;
}
使用 lua_getglobal(L, name)
函数,获取名为name的变量并置于栈顶,变量名可以是定义的全局变量,也可以是函数名。在用 lua_tostring(L, index)
/ lua_tonumber(L, index)
/ lua_tointeger(L, index)
来获取这个变量。
lua_getglobal(L, "str");
string str = lua_tostring(L, -1);
cout << "str: " << str << endl;
使用 lua_getglobal(L, name)
将 table 变量置于栈顶,然后利用 lua_getfield(L, -1, key)
来获取 key 所对应的变量并置于栈顶,然后在获取该变量即可。
lua_getglobal(L, "tbl");
lua_getfield(L, -1, "name");
string name = lua_tostring(L, -1);
lua_getfield(L, -2, "id");
int id_ = (int) lua_tointeger(L, -1);
cout << "table.name = " << name << endl;
cout << "table.id = " << id << endl;
使用 lua_getglobal(L, name)
将函数置于栈顶,然后再调用 lua_push*
传入参数,并调用 lua_pcall(L, param_num, return_num, 0)
来调用函数,调用完成后返回值会存放在栈顶中。
lua_getglobal(L, "add");
lua_pushnumber(L, 123);
lua_pushnumber(L, 145);
lua_pcall(L, 2, 1, 0);
double res = lua_tonumber(L, -1);
cout << "123 + 145 = " << res << endl;
main.cpp
完整代码#include <iostream>
#include <string>
extern "C" {
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
}
using namespace std;
int main() {
// 1. 创建一个state
lua_State *L = luaL_newstate();
luaL_openlibs(L);
// 2. 绑定和执行 Lua
int bRet;
/*
bRet = luaL_loadfile(L, "../lua_code/add.lua");
if (bRet) {
cout << "Load Lua file error." << endl;
return 1;
}
bRet = lua_pcall(L, 0, 0, 0);
if (bRet) {
cout << "Call Lua file error." << endl;
return 1;
}
*/
bRet = luaL_dofile(L, "../lua_code/add.lua");
if (bRet) {
cout << "load and run lua file error" << endl;
return 1;
}
lua_getglobal(L, "str");
string str = lua_tostring(L, -1);
cout << "str: " << str << endl;
cout << "----------------" << endl;
lua_getglobal(L, "tbl");
lua_getfield(L, -1, "name");
string name = lua_tostring(L, -1);
lua_getfield(L, -2, "id");
int id_ = (int) lua_tointeger(L, -1);
cout << "table.name = " << name << endl;
cout << "table.id = " << id_ << endl;
cout << "----------------" << endl;
lua_getglobal(L, "add");
lua_pushnumber(L, 123);
lua_pushnumber(L, 145);
lua_pcall(L, 2, 1, 0);
double res = lua_tonumber(L, -1);
cout << "123 + 145 = " << res << endl;
return 0;
}
目前为止已经建立了 src/main.cpp
以及 lua_code/add.lua
两个文件,接下来就是如何运行的问题。由于 Lua 已经编译为了库文件,在 Lua 安装目录的 src
子目录中,该目录中也存放了 Lua 库的头文件,所以在 CMakeLists.txt
文件中添加上头文件以及库文件路径,并将 Lua 库文件链接到生成的目标文件中即可。
cmake 语法这里不再详细说明,首先在项目目录中创建 CMakeLists.txt
文件,内容如下:
cmake_minimum_required(VERSION 3.10)
project(CppCallLua)
add_subdirectory(./src)
然后在 src
子目录中再创建一个 CMakeLists.txt
文件,用于编译源目录下文件:
# 添加 lua 头文件以及库文件路径
include_directories(/Users/gongqinkang/apps/lua-5.3.5/src)
link_directories(/Users/gongqinkang/apps/lua-5.3.5/src)
# 设置可执行文件的输出目录为 build/bin/
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
# 添加可执行文件
aux_source_directory(. DIR_SRC)
add_executable(main ${DIR_SRC})
# 链接 lua 库
target_link_libraries(main lua)
在项目文件中创建 build
目录,此时整个项目目录结构为:
然后 cd
进入 build
目录,在 build
目录下运行:
> cmake ..
> make
cmake 会生成 Makefile
文件,然后用 make
进行编译,最后产生的可执行文件在 build/bin/
目录下,然后在 build
目录下输入:
> ./bin/main
即可运行,运行结果如下:
标签:接下来 一个 code exec info ace 比较 clu VID
原文地址:https://www.cnblogs.com/gongqk/p/14626536.html