先来说下大致脚本引擎框架,此次采用如下,即运行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 <iostream>
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" int
extern "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 <stdio.h>
#include <string.h>
#include <string> #include <CLua.h> extern "C" {
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
} 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 <stdio.h>
#include <string.h>
#include <CLua.h> 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;
}

测试结果

代码下载

Lua C/C++互相调用的更多相关文章

  1. Lua与C++相互调用

    {--1.环境--} 为了快速入手,使用了小巧快速的vc++6.0编译器 以及在官网下载了Lua安装包..官网地址{--http://10.21.210.18/seeyon/index.jsp--} ...

  2. lua编程之lua与C相互调用

    lua是扩展性非常良好的语言,虽然核心非常精简,但是用户可以依靠lua库来实现大部分工作.除此之外,lua还可以通过与C函数相互调用来扩展程序功能.在C中嵌入lua脚本既可以让用户在不重新编译代码的情 ...

  3. Lua与C++互相调用(上)

    int main1(int argc, const char * argv[]) { lua_State* L = luaL_newstate();//创建栈 luaopen_base(L); lua ...

  4. uLua学习笔记(三):Unity3D和Lua之间的相互调用

    这篇笔记主要集中学习一下uLua和Unity3D之间相互调用的方法,我们导入了uLua之后,现在会弹出一个类似学习屏幕的东西,如下: 先赞一个! Unity3D调用Lua Unity3D调用Lua的方 ...

  5. cocos2d-x Lua与OC互相调用

    1. Lua 调用OC 先看例子: hello.lua: -- 点击回调函数 local function notifymenuCallbackTest() local luaoc = require ...

  6. 在JAVA中使用LUA脚本记,javaj调用lua脚本的函数(转)

    最近在做一些奇怪的东西,需要Java应用能够接受用户提交的脚本并执行,网络部分我选择了NanoHTTPD提供基本的HTTP服务器支持,并在Java能承载的许多脚本语言中选择了很久,比如Rhino,Jy ...

  7. C和Lua之间的相互调用

    前面的话 第一次接触Lua是因为Unity游戏中需要热更,但是一直没搞懂Lua是怎么嵌入到别的语言中执行的,如何互相调用的.这次打算好好了解一下C跟lua是如何交互的 那么如何使用Lua语言? lua ...

  8. lua语言自学知识点----Lua与.Net相互调用

    知识点: LuaInterface作用是用来完成Lua与C#的相互调用. LuaInterface核心库:1.luainterface.dll 用于C#读取lua(放在bin目录同级) 2.luane ...

  9. Lua 与 OC 相互调用

    本文主要讲如何完成lua和object-c的相互调用.       lua是一种脚本语言,可以方便的移植到各种宿主语言中,并且可以支持热更新,在游戏开发中也能当做主要的语言来编写游戏的逻辑,但是要接入 ...

随机推荐

  1. oozie调度sqoop Job 数据库密码无法保存

    问题描述 通过oozie调度sqoop作业时,需要输入数据库作业密码,但在sqoop元数据服务配置密码后,过一段时间会失效. 解决方法 将数据库密码写入HDFS文件,通过配置Sqoop job,实现传 ...

  2. Angular4中路由Router类的跳转navigate

    最近一直在学习angular4,它确实比以前有了很大的变化和改进,好多地方也不是那么容易就能理解,好在官方的文档和例子是中文,对英文不太好的还是有很大帮助去学习. 官方地址:https://angul ...

  3. Google Protobuf 使用 Java 版

    一 . Protobuf 的入门 Protobuf 是一个灵活,高效,结构化的数据序列化框架, 相比于 XML 等传统的序列化工具,它更小,更快,更灵活,更简单. Protobuf 支持数据结构化一次 ...

  4. 解决webdiyer:AspNetPager分页控件在IE模式下点击页号不能翻页的问题。

    在网站根目录下新建ie.browser文件, 然后用记事本打开. 将以下代码粘贴进去,保存即可,目的是让其与IE11的 UserAgent 匹配,使 .net framework 认识这是一个已知的浏 ...

  5. CustomDrawableTextView

    public class CustomDrawableTextView extends TextView{ //image width.height private int imageWidth; p ...

  6. C++系统自己主动生成默认构造函数的情况

    (1) 基类存在默认构造函数 class CBaseClass { public: CBaseClass() { m_i = 0; } private: int m_i; }; class CDriv ...

  7. Kafka认证权限配置(动态添加用户)

    之前写过一篇Kafka ACL使用实战,里面演示了如何配置SASL PLAINTEXT + ACL来为Kafka集群提供认证/权限安全保障,但有一个问题经常被问到:这种方案下是否支持动态增加/移除认证 ...

  8. vue filter方法-时间格式化

    plugins/filter.js import Vue from 'vue' // 时间格式化 // 用法:<div>{{data | dataFormat('yyyy-MM-dd hh ...

  9. C++ Msi函数判断应用是否已经安装

    #include <Windows.h> #include <Msi.h> #pragma comment(lib, "Msi.lib") bool Che ...

  10. git 的相关知识

    参考文章 git checkout HEAD <file> :  master/HEAD -> index -> work directory index 暂存区有两行信息.分 ...