Lua与C/C++交互——C/C++调用Lua脚本
Posted 牧秦丶
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Lua与C/C++交互——C/C++调用Lua脚本相关的知识,希望对你有一定的参考价值。
Lua与C/C++交互——C/C++调用Lua脚本
0.简介
上期介绍了如何在Lua中调用C/C++代码,本期介绍如何在C/C++中调用Lua脚本。有关Lua与C/C++交互的基础知识以及Lua堆栈操作,请见《Lua与C/C++交互——Lua调用C/C++》一文。
本期介绍一个例子,通过Lua来生成一个XML格式的便签。便签格式如下:
<?xml version="1.0" encoding="utf-8" ?>
<note>
<fromName>发送方姓名</fromName>
<toName>接收方姓名</toName>
<sendTime>发送时间</sendTime>
<msgContent>便签内容</msgContent>
</note>
我们通过C/C++来输入这些信息,然后让Lua来生成这样一个便签文件。
1. Lua代码
xmlHead = '<?xml version="1.0" encoding="utf-8" ?>\\n'
-- Open note file to wriet.
function openNoteFile(fileName)
return io.open(fileName, "w")
end
-- Close writed note file.
function closeNoteFile(noteFile)
noteFile:close()
end
function writeNestedLabel(ioChanel, label, nestCnt)
if nestCnt == 0 then
ioChanel:write(label)
return
end
for i = 1, nestCnt do
ioChanel:write("\\t")
end
ioChanel:write(label)
end
function generateNoteXML(fromName, toName, msgContent)
local noteFile = openNoteFile(fromName .. "_" .. toName .. ".xml")
if not noteFile then
return false
end
noteFile:write(xmlHead)
noteFile:write("<note>\\n")
local currNestCnt = 1
writeNestedLabel(noteFile, "<fromName>", currNestCnt)
noteFile:write(fromName)
writeNestedLabel(noteFile, "</fromName>\\n", 0)
writeNestedLabel(noteFile, "<toName>", currNestCnt)
noteFile:write(toName)
writeNestedLabel(noteFile, "</toName>\\n", 0)
local sendTime = os.time()
writeNestedLabel(noteFile, "<sendTime>", currNestCnt)
noteFile:write(sendTime)
writeNestedLabel(noteFile, "</sendTime>\\n", 0)
writeNestedLabel(noteFile, "<msgContent>", currNestCnt)
noteFile:write(msgContent)
writeNestedLabel(noteFile, "</msgContent>\\n", 0)
noteFile:write("</note>\\n")
closeNoteFile(noteFile)
return true
end
我们通过openNoteFile和closeNoteFile来打开/关闭XML文件。generateNoteXML全局函数接受发送方姓名、接收方姓名、便签内容,生成一个XML便签文件。便签发送时间通过Lua标准库os.time()函数来获取。writeNestedLabel函数根据当前XML的缩进数目来规范XML输出格式。此文件很好理解,不再赘述。
2.C++调用Lua脚本
extern "C"
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#pragma comment(lib, "lua.lib")
;
#include <iostream>
#include <string>
using namespace std;
//
// 初始化Lua环境.
//
lua_State* initLuaEnv()
lua_State* luaEnv = lua_open();
luaopen_base(luaEnv);
luaL_openlibs(luaEnv);
return luaEnv;
//
// 加载Lua文件到Lua运行时环境中.
//
bool loadLuaFile(lua_State* luaEnv, const string& fileName)
int result = luaL_loadfile(luaEnv, fileName.c_str());
if (result)
return false;
result = lua_pcall(luaEnv, 0, 0, 0);
return result == 0;
//
// 获取全局函数.
//
lua_CFunction getGlobalProc(lua_State* luaEnv, const string& procName)
lua_getglobal(luaEnv, procName.c_str());
if (!lua_iscfunction(luaEnv, 1))
return 0;
return lua_tocfunction(luaEnv, 1);
int main()
// 初始化Lua运行时环境.
lua_State* luaEnv = initLuaEnv();
if (!luaEnv)
return -1;
// 加载脚本到Lua环境中.
if (!loadLuaFile(luaEnv, ".\\\\GenerateNoteXML.lua"))
cout<<"Load Lua File FAILED!"<<endl;
return -1;
// 获取Note信息.
string fromName;
string toName;
string msgContent;
cout<<"Enter your name:"<<endl;
cin>>fromName;
cout<<"\\nEnter destination name:"<<endl;
cin>>toName;
cout<<"\\nEnter message content:"<<endl;
getline(cin, msgContent);
getline(cin, msgContent);
// 将要调用的函数和函数调用参数入栈.
lua_getglobal(luaEnv, "generateNoteXML");
lua_pushstring(luaEnv, fromName.c_str());
lua_pushstring(luaEnv, toName.c_str());
lua_pushstring(luaEnv, msgContent.c_str());
// 调用Lua函数(3个参数,一个返回值).
lua_pcall(luaEnv, 3, 1, 0);
// 获取返回值.
if (lua_isboolean(luaEnv, -1))
int success = lua_toboolean(luaEnv, -1);
if (success)
cout<<"\\nGenerate Note File Successful!"<<endl;
// 将返回值出栈.
lua_pop(luaEnv, 1);
// 释放Lua运行时环境.
lua_close(luaEnv);
system("pause");
return 0;
//:-)
3.代码解析
3.1.初始化Lua运行时环境
lua_State*所指向的结构中封装了Lua的运行时环境。我们用initLuaEnv这个函数来初始化。lua_open函数用来获取一个新环境,然后我们用luaopen_base打开Lua的基础库,然后用luaL_openlibs打开Lua的io、string、math、table等高级库。
3.2.加载Lua文件
然后我们用luaL_loadfile和lua_pcall来将一个Lua脚本加载到对应的Lua运行时环境中——注意:并不自动执行,只是加载。这两个函数如果返回非0,表示加载失败——你的Lua脚本文件可能未找到或Lua脚本有语法错误……
3.3.加载Lua函数
我们用lua_getglobal函数将Lua脚本中的全局函数、全局变量等入栈,放在栈顶。
3.4.压入Lua函数调用参数
我们用lua_push系列函数来将要调用函数所需参数全部入栈,入栈顺序为Lua函数对应参数从左到右的顺序。
3.5.调用Lua函数
最后用lua_pcall来调用函数。Lua_pcall函数原型如下:
int lua_pcall(lua_State* L, int nargs, int nresults, int errfunc);
其中,L为此函数执行的Lua环境,nargs为此函数所需的参数个数,nresults为此函数的返回值个数,errfunc为发生错误时错误处理函数在堆栈中的索引。
3.6.获取Lua函数返回值
然后,我们可以通过检测栈顶的位置(从-1开始),来获取返回值。获取返回值后,用lua_pop将栈顶元素出栈——出栈个数为返回值个数。
3.7.释放Lua环境
最后,通过lua_close函数来关闭Lua环境并释放资源。
4.运行结果
我们将GenerateNoteXML.lua脚本和最终的C++生成的GenerateNoteXML.exe放在同一路径下,并运行GenerateNoteXML.exe,在此目录下会生成一个XML文件。如下:
生成的arnozhang_YaFengZhang.xml文件如下:
以上是关于Lua与C/C++交互——C/C++调用Lua脚本的主要内容,如果未能解决你的问题,请参考以下文章