博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Lua C/C++互相调用
阅读量:4672 次
发布时间:2019-06-09

本文共 8759 字,大约阅读时间需要 29 分钟。

      先来说下大致脚本引擎框架,此次采用如下,即运行C++代码启动程序,然后加载Lua脚本执行!

1.基础

   Lua脚本中只能调用 int (*lua_CFunction) (lua_State *L) 这种类型的C/C++函数;

   所有的C/C++函数如果要给Lua进行调用,只能用这样的函数来封装;

   那么在C/C++中怎么获得Lua传递过来的参数? 通过操作Lua 虚拟机的栈 !下面我们来了解Lua堆栈!

   Lua C/C++互相调用应用:

    (1)Lua可以让程序员开发在Lua脚本中调用C/C++函数的接口,这个接口称做LuaGlue函数,因为它们可以在Lua环境中整合C/C++的功能。

    (2)Lua API提供了函数让C++代码也可以直接调用Lua函数,还提供了方法可以传递字符和长文字给Lua解释。

    综合上面两点所述,C/C++代码和Lua脚本之间的交互是双向的!

 

2.了解Lua栈

   Lua和C/C++语言通信的主要方法是一个Lua的虚拟栈,栈的特点是先进后出。

   在Lua中,Lua堆栈就是一个struct,堆栈索引的方式可是是正数也可以是负数,区别是:正数索引1永远表示栈底,负数索引-1永远表示栈顶!

3.Lua常用函数()

4.简单封装1

   .h文件

#ifndef __LUA_WRAPPER_H__#define __LUA_WRAPPER_H__extern "C"{#include "lua.h"  #include "lauxlib.h"  #include "lualib.h"  #pragma comment(lib, "liblua.dll.a")}class CLuaWrapper{public:	// 初始化	static void init();	// 退出	static void exit();	// 执行	static bool exe_lua_file(const char* fileName);	// 注册C++函数到lua	static void reg_fun2Lua(const char* funName, int(*c_fun)(lua_State* L));};#endif

.cpp文件

#include "LuaWrapper.h"lua_State* g_lua_state = nullptr;// 获取Lua栈内信息// 获取Lua文件名 行数//static void do_log_message(void(*log)(const char* file_name, int line_num, const char* msg), const char* msg) //{//	lua_Debug info;//	int depth = 0;//	while (lua_getstack(g_lua_state, depth, &info)) {////		lua_getinfo(g_lua_state, "S", &info);//		lua_getinfo(g_lua_state, "n", &info);//		lua_getinfo(g_lua_state, "l", &info);////		if (info.source[0] == '@') {//			log(&info.source[1], info.currentline, msg);//			return;//		}////		++depth;//	}//	if (depth == 0) {//		log("trunk", 0, msg);//	}//}////void log_print(const char* file_name, int line_num, const char* msg)//{//	printf("%s:%d \r\n%s\r\n", file_name, line_num, msg);//}void CLuaWrapper::init(){	g_lua_state = luaL_newstate();	luaL_openlibs(g_lua_state);}void CLuaWrapper::exit(){	if (g_lua_state != nullptr)	{		lua_close(g_lua_state);		g_lua_state = nullptr;	}}bool CLuaWrapper::exe_lua_file(const char* fileName){	if (luaL_dofile(g_lua_state, fileName))	{		// 发生错误时		//const char* msg = luaL_checkstring(g_lua_state, -1);		//if (msg) { // file_name, line_num		//	do_log_message(log_print, msg);		//}		return false;	}	return true;}void CLuaWrapper::reg_fun2Lua(const char* funName, int(*c_fun)(lua_State* L)){	lua_pushcfunction(g_lua_state, c_fun);	lua_setglobal(g_lua_state, funName);}

测试小Demo1

 (1)新建一个Lua文件,test.lua  具体如下:

print("========Lua脚本=======")--add为C导入Lua函数sum = add(10,20)print("计算结果为:")print(sum)print("========Lua脚本=======")

 (2)建立一个控制台程序如下:

#include 
using namespace std;#include "LuaWrapper.h"// 原函数static int add(int x, int y){ return x + y;}// 给Lua调用的函数static int add_tolua(lua_State* L){ printf("此处被Lua调用了!\r\n"); // 此处获取Lua传过来的参数 /* 得到参数个数 */ int n = lua_gettop(L); printf("add函数(Lua脚本内)传参个数:%d个\r\n", n); //int x = 0, y = 0; //if (lua_isnumber(L, -1)) { // y = lua_tonumber(L, -1); //} //if (lua_isnumber(L, -2)) { // x = lua_tonumber(L, -2); //} int y = luaL_checkint(L, -1); int x = luaL_checkint(L, -2); // end // 调用C函数 int sum = add(x, y); // 结果压入Lua栈 lua_pushnumber(L, sum); // end // 返回1个值 return 1; }int main(){ //1.初始化Lua CLuaWrapper::init(); // 注册函数 CLuaWrapper::reg_fun2Lua("add", add_tolua); // 执行Lua脚本 CLuaWrapper::exe_lua_file("test.lua"); // 退出关闭Lua CLuaWrapper::exit(); system("pause"); return 0;}

执行结果如下:

5.简单封装2

---先创建有个CLua类

.h文件

#ifndef __CLUA_H__#define __CLUA_H__struct lua_State;#define LuaGlue extern "C" intextern "C" {// Lua内调用C的函数格式typedef int (*LuaFunctionType)(struct lua_State *pLuaState);};class CLua{public:	CLua();	virtual ~CLua();	// ====脚本运行错误时调用m_pErrorHandler函数(该函数被设置才被调用)============	// 运行脚本 高级版本Lua的dofile	bool		RunScript(const char *pFilename);	// 运行命令 高级版本Lua的doString	bool		RunString(const char *pCommand);	// end========================================================================	// 获取错误	const char *GetErrorString(void);	// 向Lua添加函数	bool		AddFunction(const char *pFunctionName, LuaFunctionType pFunction);	// num:索引	// Lua栈内索引为num位置的值是字符串则返回,否则返回默认值NULL	const char *GetStringArgument(int num, const char *pDefault=NULL);	// num:索引	// Lua栈内索引为num位置的值是数字则返回,否则返回默认值0.0	double		GetNumberArgument(int num, double dDefault=0.0);	// 压入一个字符进入Lua栈	void		PushString(const char *pString);	// 压入一个数字进入Lua栈	void		PushNumber(double value);	// 设置错误处理函数	void		SetErrorHandler(void(*pErrHandler)(const char *pError)) {m_pErrorHandler = pErrHandler;}	// 获取lua_State	lua_State	*GetScriptContext(void)		{return m_pScriptContext;}private:	// lua_State	lua_State	*m_pScriptContext;	// 错误处理函数	void(*m_pErrorHandler)(const char *pError);};#endif

.cpp文件

#include 
#include
#include
#include
extern "C" {#include
#include
#include
}CLua::CLua(){ m_pErrorHandler = NULL; // 老版本5.0.2==================== // 创建Lua m_pScriptContext = lua_open(); // 加载库文件 luaopen_base(m_pScriptContext); luaopen_io(m_pScriptContext); luaopen_string(m_pScriptContext); luaopen_math(m_pScriptContext); luaopen_debug(m_pScriptContext); luaopen_table(m_pScriptContext); // end // 新版本5.3用以下内容 //m_pScriptContext = luaL_newstate(); //luaL_openlibs(m_pScriptContext); // end}CLua::~CLua(){ // 释放资源 if(m_pScriptContext) lua_close(m_pScriptContext);}static std::string findScript(const char *pFname){ FILE *fTest; char drive[_MAX_DRIVE]; char dir[_MAX_DIR]; char fname[_MAX_FNAME]; char ext[_MAX_EXT]; _splitpath( pFname, drive, dir, fname, ext ); std::string strTestFile = (std::string) drive + dir + "Scripts\\" + fname + ".LUB"; fTest = fopen(strTestFile.c_str(), "r"); if(fTest == NULL) { //not that one... strTestFile = (std::string) drive + dir + "Scripts\\" + fname + ".LUA"; fTest = fopen(strTestFile.c_str(), "r"); } if(fTest == NULL) { //not that one... strTestFile = (std::string) drive + dir + fname + ".LUB"; fTest = fopen(strTestFile.c_str(), "r"); } if(fTest == NULL) { //not that one... //not that one... strTestFile = (std::string) drive + dir + fname + ".LUA"; fTest = fopen(strTestFile.c_str(), "r"); } if(fTest != NULL) { fclose(fTest); } return strTestFile;}bool CLua::RunScript(const char *pFname){ std::string strFilename = findScript(pFname); const char *pFilename = strFilename.c_str(); // ==== 新版本用luaL_dofile替代以下2步骤============== if (0 != luaL_loadfile(m_pScriptContext, pFilename)) { if(m_pErrorHandler) { char buf[256]; sprintf(buf, "Lua Error - Script Load\nScript Name:%s\nError Message:%s\n", pFilename, luaL_checkstring(m_pScriptContext, -1)); m_pErrorHandler(buf); } return false; } if (0 != lua_pcall(m_pScriptContext, 0, LUA_MULTRET, 0)) { if(m_pErrorHandler) { char buf[256]; sprintf(buf, "Lua Error - Script Run\nScript Name:%s\nError Message:%s\n", pFilename, luaL_checkstring(m_pScriptContext, -1)); m_pErrorHandler(buf); } return false; } // end return true;}bool CLua::RunString(const char *pCommand){ // ==== 新版本用luaL_doString替代以下2步骤============== if (0 != luaL_loadbuffer(m_pScriptContext, pCommand, strlen(pCommand), NULL)) { if(m_pErrorHandler) { char buf[256]; sprintf(buf, "Lua Error - String Load\nString:%s\nError Message:%s\n", pCommand, luaL_checkstring(m_pScriptContext, -1)); m_pErrorHandler(buf); } return false; } if (0 != lua_pcall(m_pScriptContext, 0, LUA_MULTRET, 0)) { if(m_pErrorHandler) { char buf[256]; sprintf(buf, "Lua Error - String Run\nString:%s\nError Message:%s\n", pCommand, luaL_checkstring(m_pScriptContext, -1)); m_pErrorHandler(buf); } return false; } return true;}const char *CLua::GetErrorString(void){ return luaL_checkstring(m_pScriptContext, -1);}bool CLua::AddFunction(const char *pFunctionName, LuaFunctionType pFunction){ lua_register(m_pScriptContext, pFunctionName, pFunction); return true;}const char *CLua::GetStringArgument(int num, const char *pDefault){ return luaL_optstring(m_pScriptContext, num, pDefault);}double CLua::GetNumberArgument(int num, double dDefault){ return luaL_optnumber(m_pScriptContext, num, dDefault);}void CLua::PushString(const char *pString){ lua_pushstring(m_pScriptContext, pString);}void CLua::PushNumber(double value){ lua_pushnumber(m_pScriptContext, value);}

main测试小Demo

#include 
#include
#include
LuaGlue _Version(lua_State *L){ puts("Lua控制台测试版本1.0"); return 0;}char gpCommandBuffer[254];const char *GetCommand(void){ printf("=====> "); return gets_s(gpCommandBuffer, 254); puts("\n");}void main(void){ // 打印说明 puts("========================="); puts("||Lua控制台接收输入命令||"); puts("||请输入Lua脚本,[Q]退出||"); puts("========================="); CLua *pLua = new CLua; pLua->AddFunction("version", _Version); // 处理命令 const char *pCommand = GetCommand(); while(stricmp(pCommand, "Q") != 0) { // 将字符串传递给CLua if(!pLua->RunString(pCommand)) { printf("错误:%s\n", pLua->GetErrorString()); } // 获取下一个命令 pCommand = GetCommand(); } delete pLua;}

测试结果

转载于:https://www.cnblogs.com/jadeshu/p/10663548.html

你可能感兴趣的文章
lintcode-87-删除二叉查找树的节点
查看>>
Creating a blocking Queue<T> in .NET
查看>>
621. Task Scheduler
查看>>
IIS支持flv文件
查看>>
目标反射回波检测算法及其FPGA实现 之二:互相关/卷积/FIR电路的实现
查看>>
[Linux]常用命令与目录全拼
查看>>
并查集详解 (转)
查看>>
Junit测试Controller(MockMVC使用),传输@RequestBody数据解决办法
查看>>
jQuery Post
查看>>
从总数中生成一定数量的随机数
查看>>
Strut2页面传参跳转 --Struts2
查看>>
5.User Interface/ActionBar
查看>>
Integer 与 int 中的 ==
查看>>
ReactJS实用技巧(1):JSX与HTML的那些不同
查看>>
java语言程序设计(基础篇) 第2章 基本程序设计 课本源代码
查看>>
装饰者模式 详解
查看>>
【模板】卢卡斯定理
查看>>
[POJ 1273]Drainage Ditches
查看>>
[CODEVS 1036]商务旅行
查看>>
编写高质量代码改善C#程序的157个建议——建议50:在Dispose模式中应区别对待托管资源和非托管资源...
查看>>