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是一种脚本语言,可以方便的移植到各种宿主语言中,并且可以支持热更新,在游戏开发中也能当做主要的语言来编写游戏的逻辑,但是要接入 ...
随机推荐
- Oracle分析函数-nulls first/nulls last
select * from criss_sales; 通过rank().dense_rank().row_number()对记录进行全排列.分组排列取值但有时候,会遇到空值的情况,空值会影响得到的结果 ...
- WireShark如何抓取本地localhost的包
今天将自己的电脑既作为客户端又作为服务端进行一个程序的测试,想着用WireShark来抓包分析一下问题,但由于WireShark只能抓取经过电脑网卡的包,由于我是使用localhost或者127.0. ...
- Swagger Annotation 详解
在软件开发行业,管理文档是件头疼的事.不是文档难于撰写,而是文档难于维护,因为需求与代码会经常变动,尤其在采用敏捷软件开发模式的系统中.好的工具能够提高团队沟通效率,保证系统质量以及缩短项目的交付周期 ...
- Java 8 时间日期
啦啦啦 package lime.java1_8.time; import java.time.*; import java.time.format.DateTimeFormatter; import ...
- 【面试题】java面试题整理(有空再贴答案)
面试题+基础 各家的面试题其实都大同小异, 掌握基础和原理,走到哪都不怕. 基础 leetcode上有一些总结,star数非常高了.贴上url https://github.com/CyC2018/C ...
- java httpclient post xml demo
jar archive: http://archive.apache.org/dist/httpcomponents/ 基于httpclient 2.0 final的demo(for jdk1.5/1 ...
- GetLastError获取到错误代码的含义
在写win32的时候我们会用到GetLastError()函数来获取程序错误信息,那我们如何从返回的数字得到错误信息. 这里推荐一个博客,总结了所以返回数字的错误信息: http://blog.csd ...
- meat标签
1.文档兼容模式的定义 Edge 模式告诉 IE 以最高级模式渲染文档,也就是任何 IE 版本都以当前版本所支持的最高级标准模式渲染,避免版本升级造成的影响.简单的说,就是什么版本 IE 就用什么版本 ...
- roadhog 介绍
官方网站:https://www.npmjs.com/package/roadhog; 项目搭建demo: https://github.com/ght5935/antd-dva-less-webpa ...
- Codeforces 706C - Hard problem - [DP]
题目链接:https://codeforces.com/problemset/problem/706/C 题意: 给出 $n$ 个字符串,对于第 $i$ 个字符串,你可以选择花费 $c_i$ 来将它整 ...