Lua can be embedded and extended with code or applications written in other languages. Code and values in another language can be exposed to Lua and vice-versa.
Lua是一门嵌入式语言,提供了完备的 C API 使Lua 代码可以很方便的和其他宿主程序相互调用来扩展程序功能。
Lua与C语言的交互:在C中嵌入Lua脚本可以让用户在不重新编译代码的情况下只修改Lua代码来更新程序。在Lua中调用C函数则可以提高程序的运行效率。
一、搭建环境
根据自己使用的操作系统来搭建lua环境(这里使用 Win + VS2017 ,Lua 5.3)。
二、理解C API
Lua和C交互的部分称为C API。C API是一个C代码与Lua进行交互的函数集。
主要构成:
重要的Lua头文件:
三、理解Lua堆栈
Lua和C之间通过一个虚拟的Lua栈来进行数据交换,Lua和C之间的相互调用,即是通过Lua C API 来对Lua栈进行操作。
(1) 引入Lua头文件
C代码:
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
C++代码:
#include <lua.hpp>
(2) 创建lua_State
lua_State: An opaque structure that points to a thread and indirectly (through the thread) to the whole state of a Lua interpreter. The Lua library is fully reentrant: it has no global variables. All information about a state is accessible through this structure.
A pointer to this structure must be passed as the first argument to every function in the library, except to lua_newstate, which creates a Lua state from scratch.
lua_State:
lua_State *L = luaL_newstate();
(3) 打开所需的Lua库
luaL_openlibs(L);
(4) 加载、运行Lua代码
if (luaL_dofile(L, fileName))
cout << "Failed to load the lua script ." << endl;
将Lua代码文件作为Lua代码块加载并运行,如果没有错误则返回false,等同于代码:
if(luaL_loadfile(L,fileName) || lua_pcall(L,0,0,0))
cout << "Failed to load the lua script ." << endl;
其中,luaL_loadfile、luaL_load_filex、luaL_loadstring都和lua_load函数一样,都是只加载代码块而不运行它,如果没有错误,lua_load函数会将编译后的代码块作为一个Lua函数压入Lua虚拟栈的顶部,否则,则会向Lua栈内压入一条错误信息,该错误信息可以使用lua_tostring(L,-1)取出。
lua_load: Loads a Lua chunk without running it. If there are no errors, lua_load pushes the compiled chunk as a Lua function on top of the stack. Otherwise, it pushes an error message.
随即用lua_pcall(L,0,0,0)在保护模式下调用刚才压入栈的Lua函数(即给定的Lua代码文件),和lua_call一样,lua_pcall也会将函数以及函数的参数从Lua栈上移除。
lua_pcall: Calls a function in protected mode.Like lua_call, lua_pcall always removes the function and its arguments from the stack.
(5) 进行虚拟栈操作
lua_getglobal(L, "add");
lua_pushnumber(L, 10);
lua_pushnumber(L, 20);
if (lua_pcall(L, 2, 1, 0))
cout << "Failed to call the lua func ." << endl;
(6) 获取操作执行结果
res = lua_tonumber(L, -1);
lua_pop(L,1);
(7) 关闭Lua栈
lua_close(L);
完整代码( Win + VS2017,Lua 5.3):
//file: luaTest.cpp
#include "pch.h"
#include <lua.hpp>
#include <direct.h>
#include <iostream>
using namespace std;
void echoCwd()
{
char buffer[_MAX_PATH];
_getcwd(buffer, _MAX_PATH);
cout << "Current Work Directory : " << buffer << endl;
}
int luaAdd(lua_State *L ,const char *fileName , int x, int y)
{
int res = 0;
if (luaL_dofile(L, fileName))
cout << "Failed to load this lua script ." << endl;
lua_getglobal(L, "add");
lua_pushnumber(L, 10);
lua_pushnumber(L, 20);
if (lua_pcall(L, 2, 1, 0))
cout << "Failed to call this lua func ." << endl;
res = lua_tonumber(L, -1);
lua_pop(L,1);
return res;
}
int main()
{
//Make sure the file add.lua is in the right place or you can use orther filePath .
const char *fileName = "add.lua";
echoCwd();
int res = 0;
lua_State *L = luaL_newstate();
luaL_openlibs(L);
res = luaAdd(L,fileName,10,20);
cout << "res = " << res << endl;
lua_close(L);
char c;
cin >> c;
return 0;
}
Lua代码:
--file: add.lua
add = function (x, y)
return x + y
end
Build:
运行并输出:
Current Work Directory : *****//你项目的当前路径
res = 30
(1)-(4)步类比C调用Lua函数的步骤
(5) 进行虚拟栈操作
查询表的值:
lua_getglobal(L, "tipswin");
lua_getfield(L, -1, "content");
等同于代码:
lua_getglobal(L,"tipswin");
lua_pushstring(L,"name");
lua_gettable(L,-2);
lua_getfield或者lua_gettable之后,压入栈的表以及key值参数都将被出栈,之后将查询到的返回值入栈
修改表的值:
lua_getglobal(L, "tipswin");
lua_pushstring(L, "Time Waits For No One .");
lua_setfield(L,-2,"content");
lua_pop(L, -1);
完整代码:
//file: luaTest.cpp
#include "pch.h"
#include <lua.hpp>
#include <Cstring>
#include <iostream>
using namespace std;
int main()
{
lua_State *L = luaL_newstate();
luaL_openlibs(L);
//Make sure the file luaCode.lua is in the right place or you can use orther file path .
const char *fileName = "luaCode.lua";
if(luaL_dofile(L, fileName))
cout << "Failed to load this lua script ." << endl;
//方式一
lua_getglobal(L,"tipswin");
lua_pushstring(L,"name");
lua_gettable(L,-2);
string name = lua_tostring(L,-1);
cout << "TipsWin's Name is : " << name.c_str() << endl;
lua_pop(L,-1);
//方式二
lua_getglobal(L, "tipswin");
lua_getfield(L, -1, "content");
string content = lua_tostring(L, -1);
cout << "TipsWin's Content is : " << content.c_str() << endl;
lua_pop(L, -1);
//修改Lua表中的值
lua_getglobal(L, "tipswin");
lua_pushstring(L, "Time Waits For No One .");
lua_setfield(L,-2,"content");
lua_pop(L, -1);
//修改之后的Content
lua_getglobal(L, "tipswin");
lua_getfield(L, -1, "content");
content = lua_tostring(L, -1);
cout << "After Modify The TipsWin's Content is : " << content.c_str() << endl;
lua_pop(L, -1);
lua_close(L);
char c;
cin >> c;
return 0;
}
当前工作路径下Lua代码:
--file: luaCode.lua
tipswin = {name = "Tips",content= "Please Notice this Window ."}
输出结果:
文档:
http://www.lua.org/manual/5.3/manual.html
http://lua-users.org/wiki/BindingCodeToLua
博客:
https://www.jb51.net/article/132851.htm
https://blog.csdn.net/alexwoo0501/article/details/50916037
原文:https://www.cnblogs.com/sylvan/p/9862758.html