您的位置:首页 > 编程语言 > Lua

Lua与C/C++交互——C/C++调用Lua脚本

2011-10-07 15:24 731 查看
                                                                                   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文件如下:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息