[转]LUA C 互调
LUA和C之间的函数调用
1.1 从C程序调用LUA函数
LUA的函数和普通变量一样也是First Class Variable类型,可以看作函数指针变量参与栈操作。因此调用过程分为如下几个步骤:
- 请求LUA函数(指针)入(GLOBAL)栈。
- 将函数需要的参数入栈,入栈顺序按照参数被声明的顺序。
- 告知LUA虚拟机入栈参数的个数、函数返回值的个数,并调用此LUA函数。
- 从栈定获得返回值,先返回的先入栈,然后将返回值显式出栈。
1.2 从LUA脚本调用C函数
LUA没有提供PYTHON那样丰富的类库,因此复杂的功能需要在C程序中定义好,然后通过lua决定调用时机。在LUA库中定义了可以被LUA虚拟机识别的C函数模型:
这样的函数被是一个合法的lua_CFunction类型,将函数注册到LUA虚拟机中以后,就可以在LUA中以普通LUA函数的方式被调用。注册一个C函数的步骤如下:
- 声明并定义一个满足上述模型的函数 (eg. myFunInC)
- 用字符串为此C函数取一个名称并入栈(eg. myFunInLua)
- 将函数(指针)入栈
- 调用LUA库的注册函数功能,将上述的名称与函数指针关联
这样就可以在LUA中用myFunInLua()来调用C中的int myFunInC()了
2. 从C调用LUA函数示例
在下面的代码中,我们调用了LUA脚本中的fnEx2函数,返回值从栈中取得,并且要手动出栈。这里,入栈的函数参数会由pcall自动清理。
2.1 LUA测试脚本代码
function fnex2(str_a, num_b, num_c)
print(str_a);
return num_b*100 + num_c*10, "Thank you";
end;2.2 VC代码
//初始化LUA虚拟机
void InitLuaState(lua_State* L)
{
/* Load Libraries */
luaopen_base(L);
luaopen_table(L);
luaL_openlibs(L);
luaopen_string(L);
luaopen_math(L);
}
int call_lua_function(void)
{
const char* szInParam = "This is an [IN] parameter";
const int iParam1 = 20, iParam2 = 50;
cout << "=================================" << endl
<< "02_Call_Function" << endl
<< "=================================" << endl
<< "This demo calls functions in LUA scripts." << endl
<< "Argument 1:" << szInParam << endl
<< "Argument 2:" << iParam1 << endl
<< "Argument 3:" << iParam2 << endl
<< "---------------------------------" << endl
<< "#OUTPUTS#" << endl;
lua_State* L = lua_open();
InitLuaState(L);
int iError;
/* Load Script */
iError = luaL_loadfile(L, "../test02.lua");
if (iError)
{
cout << "Load script FAILED!"
<< lua_tostring(L, -1)
<< endl;
lua_close(L);
return 1;
}
/* Run Script */
iError = lua_pcall(L, 0, 0, 0);
if (iError)
{
cout << "pcall FAILED"
<< lua_tostring(L, -1)
<< iError
<< endl;
lua_close(L);
return 1; } /* Push a FUNCTION_VAR to STACK */ lua_getglobal(L, "fnex2"); /* Push PARAMETERS to STACK */ lua_pushstring(L, szInParam); lua_pushnumber(L, iParam1); lua_pushnumber(L, iParam2); /* Call FUNCTION in LUA */ iError = lua_pcall( L, //VMachine 3, //Argument Count 2, //Return Value Count 0 ); if (iError) { cout << "pcall FAILED" << lua_tostring(L, -1) << iError << endl; lua_close(L); } /* Check Return Value Types */ if (lua_isstring(L, -1) && lua_isnumber(L, -2)) { cout << "Ret_1(string): " << lua_tostring(L, -1) << endl; cout << "Rec_2(double): " << lua_tonumber(L, -2) << endl; } else { cout << "Wrong Return Values" << endl; } /* POP STACK */ lua_pop(L,2); //只需要清理Return Value,pcall调用的入栈参数会自动清理 lua_close(L); return 0;}2.3 工具
下面的宏可以简化调用lua函数的代码:
#define CallLuaFunc(FuncName, Params, Results)
{
lua_getglobal (g_pLuaState, FuncName);
lua_call (g_pLuaState, Params, Results);
}
3. 从LUA调用C函数示例
在下面的例子中,我们注册一个名为rmath的LUA函数,他在C中的函数名为RMath_LUA()
3.1 LUA脚本代码
print (">>> LUA程序开始运行了 ");
function fnex3(num_a, num_b)
local c = rmath(num_a, num_b);
print("LUA PRINTTING:", c);
return c;
end;3.2 VC程序代码
//LUA脚本调用C函数
int call_c_function(void)
{
int iArg1 = 3, iArg2 = 10, iError;
cout << "=================================" << endl
<< "下面的程序演示从LUA脚本中调用C函数" << endl
<< "Argument 1:" << iArg1 << endl
<< "Argument 2:" << iArg2 << endl
<< "---------------------------------" << endl
<< "#OUTPUTS#" << endl;
lua_State* L = lua_open();
InitLuaState(L);
iError = luaL_loadfile(L, "../test03.lua");
if (iError) cout << "载入脚本失败" << endl;
iError = lua_pcall(L, 0, 0, 0);
if (iError) cout << "执行LUA脚本失败" << endl;
/* 将C函数(指针)压栈 */
lua_pushstring(L, "rmath");
lua_pushcfunction(L, RMath_LUA);
lua_settable(L, LUA_GLOBALSINDEX);
/* LUA函数也是变量(指针),可以压入栈 */
lua_getglobal(L, "fnex3");
/* 将提供给LUA函数的参数入栈 */
lua_pushnumber(L, iArg1);
lua_pushnumber(L, iArg2);
/* 调用LUA函数(pcall函数会自动清除入栈的变量) */
int Error = lua_pcall( L, //虚拟机指针
2, //2个参数
1, //1个返回值
0 );
if (Error) cout << "pcall调用fnex3函数失败" << endl;
/* 检验返回值类型 */
if (lua_isnumber(L, -1))
{
cout << "有1个(double)返回值 = "
<< lua_tonumber(L, -1)
<< endl; } /* 将LUA函数返回值出栈 */ lua_pop(L, 1); lua_close(L); return 0;}//可供LUA调用的C函数原型int RMath_LUA(lua_State* L){ if (!lua_isnumber(L, 1)) { lua_pushstring(L, "Arg_1不是数字"); lua_error(L); } if (!lua_isnumber(L, 2)) { lua_pushstring(L, "Arg_2不是数字"); lua_error(L); } /* GET ARGUMENT FROM STACK */ double a = lua_tonumber(L, 1); double b = lua_tonumber(L, 2); /* PUSH RESULT TO STACK */ lua_pushnumber(L, a * b); /* COUNT OF RETURN VARS*/ return 1;}4. 程序解释
4.1 调用LUA脚本中的函数
调用LUA脚本函数主要用到如下几个LUA库函数:
/* Push a FUNCTION_VAR to STACK */
lua_getglobal(L, "fnex2");
/* Push PARAMETERS to STACK */
lua_pushstring(L, szInParam);
lua_pushnumber(L, iParam1);
lua_pushnumber(L, iParam2);
/* Call FUNCTION in LUA */
iError = lua_pcall( L,3,2,0);通过lua_getglobal请求函数(指针)入栈,然后将函数参数按声明顺序入栈,调用lua_pcall执行函数。lua_pcall的第一个参数 指向LUA虚拟机,第二个参数表示栈顶有多少个函数参数,第三个参数表示此函数将返回几个值。(pcall自动清理入栈的参数,返回值则需要手动 pop。)
4.2 从LUA调用C函数
主要用到如下几个函数,为求方便您也可以自己定义这样的一个宏。
lua_pushstring(L, "rmath");
lua_pushcfunction(L, RMath_LUA);
lua_settable(L, LUA_GLOBALSINDEX);
- 函数名入栈
- lua_CFunction类型的函数指针入栈
- 调用lua_settable注册函数
这样就可以在lua脚本中调用rmath()函数了。
[转]LUA C 互调的更多相关文章
- C/C++与lua实现互调
1,在lua脚本中调用C/C++代码中的函数 在C++中定义函数时必须以lua_State为参数, 以int为返回值才能被Lua所调用. /* typedef int (*lua_CFunction) ...
- 手游项目Crash的上报
基于cocos2d-x开发的手游,免不了会遇到崩溃.闪退,在非debug状态下定位问题异常的艰难,像我们项目是在cocos2dx的基础上封装了一层,然后又与lua进行互调.因为接受C++/移动端开发比 ...
- 【cocos2d-x + Lua(2) C++和lua数据通讯之间的互调】
我们主要解决如下几个问题: 转载注明出处:http://www.cnblogs.com/zisou/p/cocos2dx-lua2.html 1,C++如何获取Lua里面的一个变量值? 2,C++如何 ...
- Lua学习 2) —— Android与Lua互调
2014-07-09 一.Android类调用lua并回调 Android调用Lua函数,同一时候把类作为參数传递过去.然后再Lua中回调类的函数 调用lua mLuaState = LuaState ...
- Lua 栈的理解
提到C++与lua互调,不可不提栈. 栈是C++和Lua相互通讯的一个地方. 首先这个栈并不是传统意义上的栈(传统的栈需要放同一种数据类型,但在网上的某些资料说,每个栈元素是一个联合体). 栈从上向下 ...
- 玩转cocos2d-x lua-binding, 实现c++与lua混合编程
引言 城市精灵GO(http://csjl.teamtop3.com/)是一款基于cocos2d-x开发的LBS社交游戏, 通过真实地图的探索, 发现和抓捕隐匿于身边的野生精灵, 利用游戏中丰富的玩法 ...
- lua调用C语言
在上一篇文章(C调用lua函数)中,讲述了如何用c语言调用lua函数,通常,A语言能调用B语言,反过来也是成立的.正如Java 与c语言之间使用JNI来互调,Lua与C也可以互调. 当lua调用c ...
- tolua++实现lua层调用c++技术分析
tolua++技术分析 cocos2dx+lua 前言 一直都使用 cocos2dx + lua 进行游戏开发,用 Lua 开发可以专注于游戏逻辑的实现,另外一方面可以实现热更新:而且 lua 是一个 ...
- cocos2d-x-lua如何导出自定义类到lua脚本环境
这篇教程是基于你的工程是cocos2d-x-lua的项目,我假设你已经完全驾驭cocos-x/samples/Lua/HelloLua工程,基本明白lua和c++互调的一些原理. 我们的目的是要在 ...
随机推荐
- 20145236 《Java程序设计》 第6周学习总结
20145236 <Java程序设计>第6周学习总结 教材学习内容总结 第十章 输入/输出 InputStream与OutputStream 串流设计的概念 Java将输入/输出抽象化为串 ...
- hadoop2.0 和1.0的区别
1. Hadoop 1.0中的资源管理方案Hadoop 1.0指的是版本为Apache Hadoop 0.20.x.1.x或者CDH3系列的Hadoop,内核主要由HDFS和MapReduce两个系统 ...
- SQL Server数据库(SQL Sever语言 函数以及SQL编程)
1.数学函数:操作一个数据,返回一个结果 --去上限: ceiling ☆select ceiling(price) from car --去下限:floor ☆select floor(price) ...
- win7_oracle11g_64位连接32位PLSQL_Developer
工具/原料 已经装好的64位Oracle数据库 window7_64位的操作系统 PLSQL_Developer 9.0以上版本(目前只有32位的):下面有下载连接! 官方的 instantcli ...
- SQL语句技巧(上个样式太差了)
以下并非本人整理,但是看后感觉相当不错,特此分享. 1.应用程序中,保证在实现功能的基础上,尽量减少对数据库的访问次数:通过搜索参数,尽量减少对表的访问行数,最小化结果集,从而减轻网络负担:能够分 ...
- 如何在win7下配置IIS?
- java邮件
我们用过很多邮件,qq,163,网易等. 一.发送邮件需要遵循smtp协议,接收邮件需要遵循pop3协议 二.发邮件的过程 假设用qq邮件 写邮件-->点 “发送” --> qq邮件服务器 ...
- php include
get_include_path 获取当前 include_path 配置选项的值,在当前代码目录未找到include文件时,则到include_path去include. set_include_ ...
- GUID vs INT Debate【转】
http://blogs.msdn.com/b/sqlserverfaq/archive/2010/05/27/guid-vs-int-debate.aspx I recently read a bl ...
- javascript密码强度验证!
//CharMode函数 //测试某个字符是属于哪一类 function CharMode(iN) { if (iN>=48 && iN <=57) //数字 return ...