Lua C/C++互相调用
先来说下大致脚本引擎框架,此次采用如下,即运行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++互相调用的更多相关文章
- Lua与C++相互调用
{--1.环境--} 为了快速入手,使用了小巧快速的vc++6.0编译器 以及在官网下载了Lua安装包..官网地址{--http://10.21.210.18/seeyon/index.jsp--} ...
- lua编程之lua与C相互调用
lua是扩展性非常良好的语言,虽然核心非常精简,但是用户可以依靠lua库来实现大部分工作.除此之外,lua还可以通过与C函数相互调用来扩展程序功能.在C中嵌入lua脚本既可以让用户在不重新编译代码的情 ...
- Lua与C++互相调用(上)
int main1(int argc, const char * argv[]) { lua_State* L = luaL_newstate();//创建栈 luaopen_base(L); lua ...
- uLua学习笔记(三):Unity3D和Lua之间的相互调用
这篇笔记主要集中学习一下uLua和Unity3D之间相互调用的方法,我们导入了uLua之后,现在会弹出一个类似学习屏幕的东西,如下: 先赞一个! Unity3D调用Lua Unity3D调用Lua的方 ...
- cocos2d-x Lua与OC互相调用
1. Lua 调用OC 先看例子: hello.lua: -- 点击回调函数 local function notifymenuCallbackTest() local luaoc = require ...
- 在JAVA中使用LUA脚本记,javaj调用lua脚本的函数(转)
最近在做一些奇怪的东西,需要Java应用能够接受用户提交的脚本并执行,网络部分我选择了NanoHTTPD提供基本的HTTP服务器支持,并在Java能承载的许多脚本语言中选择了很久,比如Rhino,Jy ...
- C和Lua之间的相互调用
前面的话 第一次接触Lua是因为Unity游戏中需要热更,但是一直没搞懂Lua是怎么嵌入到别的语言中执行的,如何互相调用的.这次打算好好了解一下C跟lua是如何交互的 那么如何使用Lua语言? lua ...
- lua语言自学知识点----Lua与.Net相互调用
知识点: LuaInterface作用是用来完成Lua与C#的相互调用. LuaInterface核心库:1.luainterface.dll 用于C#读取lua(放在bin目录同级) 2.luane ...
- Lua 与 OC 相互调用
本文主要讲如何完成lua和object-c的相互调用. lua是一种脚本语言,可以方便的移植到各种宿主语言中,并且可以支持热更新,在游戏开发中也能当做主要的语言来编写游戏的逻辑,但是要接入 ...
随机推荐
- spring事务解析
1 初步理解 理解事务之前,先讲一个你日常生活中最常干的事:取钱. 比如你去ATM机取1000块钱,大体有两个步骤:首先输入密码金额,银行卡扣掉1000元钱:然后ATM出1000元钱.这两个步骤必须是 ...
- 使用DDL触发器同步多个数据库结构
使用DDL触发器同步多个数据库结构 背景:当开发组比较大时,势必会分布到不同的地理位置,若无法在同一个快速网络中工作,就会造成多个开发库并存的局面,这样就需要多个开发库结构的同步,甚至是开发测试数据的 ...
- 写在开始前---ajax中的会话过期与重新登录
一般情况下,点击<a>链接或浏览器输入url时,请求到后端,服务器判断会话是否过期.过期,重定向到登录页,或返回登录页的页面.在ajax中,返回重定向无效,这个时候就需要自己在ajax的逻 ...
- Spring data Jpa,Mybatis,读写锁,@Lock 使用
Spring data jpa 支持注解式的读写锁(悲观锁),实际上这个东西硬编码也简单,但是基于Jpa 命名方式定义的Sql,只能用注解添加支持读写锁了, 不了解读写锁的可以点这里 mysql读写锁 ...
- 【微信开发】cURL error 60: SSL certificate problem: unable to get local issuer certificate (see http://curl.haxx.se/libcurl/c/libcurl-errors.html)
在做微信开发时候,请求为你接口报错: 解决方案: 1 下载cacert https://curl.haxx.se/ca/cacert.pem 2 修改 php.ini , 并重启 curl.cainf ...
- ubuntu中python3安装package
1.实验环境 Ubuntu16.04x86 + python3.5 ubuntu中同时存在python2.7 和 python3.5 2.pip使用说明 sudo pip install packag ...
- a排兵布阵
来源hdu1166 C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务就是要监视这些工兵 ...
- PentestBox在win10里打不开工具
PentestBox详细安装过程:http://www.cnblogs.com/ESHLkangi/p/8336398.html 在使用PentestBox的时候出现了打不开工具的问题,最后看到一个老 ...
- Spring 注解配置(2)——@Autowired
版权声明:本文为博主原创文章,如需转载请标注转载地址. 博客地址:http://www.cnblogs.com/caoyc/p/5626365.html @Autowired 注释,它可以对类成员变 ...
- JDK线程池的拒绝策略
关于新疆服务请求未带入来话原因的问题 经核查,该问题是由于立单接口内部没有成功调用接续的 “更新来电原因接口”导致的,接续测更新来电原因接口编码:NGCCT_UPDATESRFLAG_PUT ,立单接 ...