lua(8)-C API 2[C++与lua的交互]
来源:互联网 发布:spring源码视频 编辑:程序博客网 时间:2024/05/29 17:38
上一篇我们提到许多c的api,这一篇我们就来看看如何实现基本的C++与lua的交互。
(1)基础示例
首先我们打开VS,新建一个c++控制台程序lua1,在我电脑上,这个新建的c++项目路径是F:\VSProject\lua1。
然后在lua的安装目录下找到include和lib文件夹
将include和lib文件夹拷贝至新建的c++项目中,拷贝到和.sln解决方案文件同一目录
拷贝完毕后,在vs中右键解决方案,找到属性
在C/C++中的“附加包含目录”加上../include
在链接器中的“附加库目录”加上../lib
附加包含目录和附加库目录添加完毕后,就可以在程序中通过#include来加载lua的头文件了。
lua1.cpp:
// lua1.cpp : 定义控制台应用程序的入口点。// #include "stdafx.h"#include "iostream"#include "stdio.h"#include "string.h"//lua.h和lualib.h作为C代码运行,在C++文件中使用lua.h和lualib.h,需使用extern命令实现混合编程,否则会提示无法解析外部函数extern "C"{ #include "lua.h" #include "lauxlib.h" #include "lualib.h"}using namespace std;#pragma comment(lib,"lua5.1.lib") int _tmain(int argc, _TCHAR* argv[]){ char buff[256]; int error; //创建一个lua状态机(虚拟栈),这个状态机没有包含预定义的lua库函数 lua_State* L = luaL_newstate(); //打开标准库,这样状态机可以使用lua库函数,可以解释lua脚本 luaL_openlibs(L); char fileName[] = "F:/LuaFile/lua1.lua"; //加载lua文件,解释器将lua文件的内容读取出来,动态编译为代码块 luaL_loadfile(L,fileName); //执行编译好的代码块,参数1为栈指针,参数2为传给待调用函数的参数数量, //参数3为期望返回的结果的数量,参数4为错误处理函数的索引(这个索引为压入栈的函数索引,0表示没有错误处理函数) int result = lua_pcall(L,0,LUA_MULTRET,0); //如果运行没有错误,lua_pcall将返回0 if(!result) { printf_s("lua脚本运行成功\n"); } lua_close(L); return 0;}
lua1.cpp新建完毕后,我们在F:/LuaFile/路径下新建一个lua1.lua文件,然后简单的写上一句打印
运行程序,看看结果
- 上面的程序使用了luaL_newstate、luaL_openlibs、luaL_loadfile、lua_pcall、lua_close这几个c api,其中luaL_newstate用于在宿主程序中创建lua的虚拟机(栈);
- 刚创建好的虚拟机是不具备lua的库环境的,因此需要luaL_openlibs函数打开lua的标准库;
- 虚拟机的环境初始化完毕后,我们使用luaL_loadfile把lua1.lua文件的内容读取出来,读取后将内容视作代码进行编译,如果编译成功,将编译后的代码块压入虚拟机中;
- 压入虚拟机中的代码块是可以被执行的,因此我们通过lua_pcall来执行这些代码块,压入的代码块正是lua1.lua中的print("I am lua1"),因此控制台中输出"Iam lua1";
- 执行结束后,关闭虚拟机,至此,一个简单的c api示例程序运行完毕。
(2)数据输入
我们修改一下main函数里面的内容
int _tmain(int argc, _TCHAR* argv[]){ char buff[256]; int loadError; int callError; //创建一个lua状态机(虚拟栈),这个状态机没有包含预定义的lua库函数 lua_State* L = luaL_newstate(); //打开标准库,这样状态机可以使用lua库函数,可以解释lua脚本 luaL_openlibs(L); //使用fgets输入流输入数据,如果使用scanf_s会受到空格的影响 while(fgets(buff,sizeof(buff),stdin) != NULL) { //接收用户输入的数据,编译为程序块并压入栈中,如果没有错误,返回0;如果有错误,压入一行错误信息的字符串 loadError =luaL_loadbuffer(L,buff,strlen(buff),"line"); if(loadError) { //打印这条错误信息,同时将错误信息压桟 printf_s("%s\n",lua_tostring(L,-1)); //弹出这条错误信息,第二个参数是从栈顶弹出元素的个数 lua_pop(L,1); } //执行代码块,并将代码块弹出栈 callError = lua_pcall(L,0,0,0); if(callError) { printf_s("%s\n",lua_tostring(L,-1)); lua_pop(L,1); } } lua_close(L); return 0;}
运行结果
- 上述程序将每一行的输入都动态编译成了lua的代码块,再通过lua_pcall函数来执行这些代码块。
通过luaL_loadbuffer函数,上述代码还可以写成这样子。
int _tmain(int argc, _TCHAR* argv[]){ char buff[256]; int loadError; int callError; //c++长字符串在每行后面用"\"接续 string luaBuff = "print('hello world');" \ "local a = 123;" \ "print(type(a));" \ "local b = 'ABC';" \ "print(type(b));" \ "function d(...)" \ "local str = 'abc^%&(';" \ "print(string.gsub(str,'%w',''));" \ "end;" \ "d();"; //创建一个lua状态机(虚拟栈),这个状态机没有包含预定义的lua库函数 lua_State* L = luaL_newstate(); //打开标准库,这样状态机可以使用lua库函数,可以解释lua脚本 luaL_openlibs(L); //接收用户输入的数据,编译为程序块并压入栈中,如果没有错误,返回0;如果有错误,压入一行错误信息的字符串 loadError =luaL_loadbuffer(L,luaBuff.c_str(),strlen(luaBuff.c_str()),"line"); if(loadError) { //打印这条错误信息,同时将错误信息压桟 printf_s("%s\n",lua_tostring(L,-1)); //弹出这条错误信息,第二个参数是从栈顶弹出元素的个数 lua_pop(L,1); } //执行代码块,并将代码块弹出栈 callError = lua_pcall(L,0,0,0); if(callError) { printf_s("%s\n",lua_tostring(L,-1)); lua_pop(L,1); } lua_close(L); return 0;}
运行结果
- 可以看到,luaBuff这个字符串的内容也被当成是lua代码块来执行了。
(3)C++与lua间的通信
上述的例子都是直接加在的一个代码块去执行它,如果c++代码中有函数fun1和fun2,lua的代码中有函数fun3和fun4,现在需要在fun1中调用fun3,在fun4中调用fun2,那么程序可以写成这样子。
lua1.cpp:
// lua1.cpp : 定义控制台应用程序的入口点。// #include "stdafx.h"#include "iostream"#include "stdio.h"#include "string.h"//lua.h和lualib.h作为C代码运行,在C++文件中使用lua.h和lualib.h,需使用extern命令实现混合编程,否则会提示无法解析外部函数extern "C"{ #include "lua.h" #include "lauxlib.h" #include "lualib.h"}using namespace std;#pragma comment(lib,"lua5.1.lib") void fun1(lua_State* L){ printf_s("I am fun1,I'll call fun3\n"); //在全局范围内获得"fun3"的这个元素,并将这个元素的内容压入栈中 lua_getglobal(L,"fun3"); int callError; callError = lua_pcall(L,0,0,0); if(callError) { printf_s("%s\n",lua_tostring(L,-1)); printf_s("call fun3 error."); lua_pop(L,1); }} int fun2(lua_State* L){ printf_s("I am fun2~~~~~~~~~\n"); //返回值的个数为0 return 0;} int _tmain(int argc, _TCHAR* argv[]){ char buff[256]; int error; //创建一个lua状态机(虚拟栈),这个状态机没有包含预定义的lua库函数 lua_State* L = luaL_newstate(); //打开标准库,这样状态机可以使用lua库函数,可以解释lua脚本 luaL_openlibs(L); char fileName[] = "F:/LuaFile/lua1.lua"; //加载lua文件,解释器将lua文件的内容读取出来,动态编译为代码块 int loadFileError = luaL_loadfile(L,fileName); //打印错误信息 if(loadFileError) { printf_s("%s\n",lua_tostring(L,-1)); lua_pop(L,1); } //向栈中压入c++的fun2 lua_pushcfunction(L,fun2); //在栈中给fun2命名为"fun2",这样其他地方就能根据"fun2"这个字段索引到fun2的内容 lua_setglobal(L,"fun2"); //执行栈中的代码块 int callError = lua_pcall(L,0,0,0); if(callError) { printf_s("%s\n",lua_tostring(L,-1)); lua_pop(L,1); } fun1(L); lua_close(L); return 0;}
然后是lua1.lua:
执行结果
可以看到,c++中的fun1调用了lua中的fun3,而lua中的fun4调用了fun2,这样就完成了最基本的交互。需要注意的是,lua_setglobal和lua_getglobal等方法需要在代码块被执行后(lua_pcall)才能生效。也就是说,如果只是把代码块加载进了栈中,但是不执行这些代码块,那么是获取不到栈中的这些全局变量的。
(4)函数的传参、返回值
我们对(3)中的lua1.cpp修改一下
lua1.cpp:
// lua1.cpp : 定义控制台应用程序的入口点。// #include "stdafx.h"#include "iostream"#include "stdio.h"#include "string.h"//lua.h和lualib.h作为C代码运行,在C++文件中使用lua.h和lualib.h,需使用extern命令实现混合编程,否则会提示无法解析外部函数extern "C"{ #include "lua.h" #include "lauxlib.h" #include "lualib.h"}using namespace std;#pragma comment(lib,"lua5.1.lib") void fun1(lua_State* L){ printf_s("I am fun1,I'll call fun3\n"); //在全局范围内获得"fun3"的这个元素,并将这个元素的内容压入栈中 lua_getglobal(L,"fun3"); //给fun3函数传参 lua_pushnumber(L,2); lua_pushnumber(L,5); int callError; //由于有fun3有两个参数,同时有一个返回值,因此lua_pcall写成lua_pcall(L,2,1,0) //lua_pcall会执行fun3方法,同时把fun3和处于栈顶的两个参数一起弹出栈,然后将fun3的返回值压桟 callError = lua_pcall(L,2,1,0); if(callError) { printf_s("%s\n",lua_tostring(L,-1)); printf_s("call fun3 error."); lua_pop(L,1); } else { //读出fun3的返回值,在栈顶 int returnNum = lua_tonumber(L,-1); printf_s("fun3 return num:%d\n",returnNum); }} int fun2(lua_State* L){ printf_s("I am fun2~~~~~~~~~\n"); //获得当前栈中被调用的函数的第一个参数,也就是"the param from fun4" const char* paramStr = luaL_checkstring(L,1); printf_s("I get the str:"); printf_s(paramStr); printf_s("\n"); //把这个参数弹出栈 lua_pop(L,1); //把返回值压入栈中 lua_pushstring(L,"fun2 getted the param."); //返回值的个数为1 return 1;} int _tmain(int argc, _TCHAR* argv[]){ char buff[256]; int error; //创建一个lua状态机(虚拟栈),这个状态机没有包含预定义的lua库函数 lua_State* L = luaL_newstate(); //打开标准库,这样状态机可以使用lua库函数,可以解释lua脚本 luaL_openlibs(L); char fileName[] = "F:/LuaFile/lua1.lua"; //加载lua文件,解释器将lua文件的内容读取出来,动态编译为代码块 int loadFileError = luaL_loadfile(L,fileName); //打印错误信息 if(loadFileError) { printf_s("%s\n",lua_tostring(L,-1)); lua_pop(L,1); } //向栈中压入c++的fun2 lua_pushcfunction(L,fun2); //在栈中给fun2命名为"fun2",这样其他地方就能根据"fun2"这个字段索引到fun2的内容 lua_setglobal(L,"fun2"); //执行栈中的代码块 int callError = lua_pcall(L,0,0,0); if(callError) { printf_s("%s\n",lua_tostring(L,-1)); lua_pop(L,1); } fun1(L); lua_close(L); return 0;}
然后修改一下lua1.lua的内容
执行程序,看看结果
可以看到c++的代码和lua的代码已经实现了相互的传参和获取返回值。
除了上述这些交互部分,还有许多种常见的数据交互,如c++中类、lua中的table等,这些部分我们在后面的篇章中再进行叙述,这篇文章就先这样了,嗯 = =。
- lua(8)-C API 2[C++与lua的交互]
- lua 与的C api交互操作
- C++与Lua交互的C API
- Lua与C的交互(2)
- 【Lua】Lua与C交互
- lua 与c的交互
- Lua与C的交互
- Lua与C的交互
- lua与c的交互
- C与Lua的交互
- Lua的与C交互
- Lua与C的交互(0)
- Lua与C的交互(1)
- Lua与C的交互(3)
- Lua 与C交互
- Lua 与 C 交互
- Lua 与C交互
- Lua 与C交互
- Android 依赖注入之Dagger
- hdu 1007 Quoit Design 最近点对(分治)
- 对I2C总线的时钟同步和总线仲裁的深入理解
- 数据库优化
- HTML与JSP页面的区别
- lua(8)-C API 2[C++与lua的交互]
- 选择算法-在线性时间内选择任意第几个小(大)的数
- 心得一、让你迅速成长的甚至成功的,从来不是努力
- Ubuntu下Sublime Text3搭建python3.5编程环境小记录
- ios获取网络接口信息的函数
- iOS 10 开发适配系列 之 网络请求
- C#中调用libvlc实现本地、网络节目流的播放
- Spring的初始化
- Spring 注入静态变量 解决方案