Lua 与 C 交互值 函数调用(2)
@(语言)
Lua和C 函数间的使用,都是通过栈来交互,并且基于遵守一定的规则,按照这个规则来就可以了。
1. 调用Lua函数
调用Lua方法过程
- 将被调用的函数入栈;
- 依次将所有参数入栈;
- 使用 lua_pcall 调用函数;
- 从栈中获取函数执行返回的结果。
** lua_pcall** 函数
lua_pcall (lua_State *L, int nargs, int nresults, int errfunc);
Calls a function in protected mode.
Both nargs and nresults have the same meaning as in lua_call. If there are no errors during the call, lua_pcall behaves exactly like lua_call. However, if there is any error, lua_pcall catches it, pushes a single value on the stack (the error message), and returns an error code. Like lua_call, lua_pcall always removes the function and its arguments from the stack.
If errfunc is 0, then the error message returned on the stack is exactly the original error message. Otherwise, errfunc is the stack index of an error handler function. (In the current implementation, this index cannot be a pseudo-index.) In case of runtime errors, this function will be called with the error message and its return value will be the message returned on the stack by lua_pcall.
Typically, the error handler function is used to add more debug information to the error message, such as a stack traceback. Such information cannot be gathered after the return of lua_pcall, since by then the stack has unwound.
The lua_pcall function returns 0 in case of success or one of the following error codes (defined in lua.h):
LUA_ERRRUN: a runtime error.
LUA_ERRMEM: memory allocation error. For such errors, Lua does not call the error handler function.
LUA_ERRERR: error while running the error handler function.
lua_pcall 时指定参数的个数和返回结果的个数,第四个参数可以指定一个错误处理函数。
在将结果入栈之前, lua_pcall 会将栈内的函数和参数移除.
如果 lua_pcall 运行时出现错误, lua_pcall 会返回一个非 0 的结果。另外,他将错误信息入栈(仍然会先将函数和参数从栈中移除)。在将错误信息入栈之前,如果指定了错误处理函数, lua_pcall会用错误处理函数。
lua_call 函数
void lua_call (lua_State *L, int nargs, int nresults);
功能与lua_pcall相同,错误时直接抛出错误,而不是返回错误码
案例:
Lua方法:
function f (x, y)
return (x^2 * math.sin(y))/(1 - x)
end
C中调用:
/* call a function `f' defined in Lua */
double f (double x, double y) {
double z;
/* push functions and arguments */
lua_getglobal(L, "f"); /* function to be called */
lua_pushnumber(L, x); /* push 1st argument */
lua_pushnumber(L, y); /* push 2nd argument */
/* do the call (2 arguments, 1 result) */
if (lua_pcall(L, 2, 1, 0) != 0)
error(L, "error running function `f': %s",
lua_tostring(L, -1));
/* retrieve result */
if (!lua_isnumber(L, -1))
error(L, "function `f' must return a number");
z = lua_tonumber(L, -1);
lua_pop(L, 1); /* pop returned value */
return z;
}
2. 调用C函数
当 Lua 调用 C 函数的时候,使用和 C 调用 Lua 相同类型的栈来交互。 C 函数从栈中获取她的参数,调用结束后将返回结果放到栈中。需要注意:
- 每个 C 函数还会返回结果的个数( the function returns (in C) the number of results it isleaving on the stack.)
- Lua调用 C 函数我们必须注册函数,也就是把 C 函数的地址以一个适当的方式传递给 Lua 解释器。
- 用来交互的栈不是全局变量,每一个函数都有他自己的私有栈。当 Lua 调用 C 函数的时候,第一个参数总是在这个私有栈的index=1 的位置。甚至当一个 C 函数调用 Lua 代码( Lua 代码调用同一个 C 函数或者其他的 C 函数),每一个 C 函数都有自己的独立的私有栈,并且第一个参数在 index=1 的位置
C 函数
C函数规范:
typedef int (*lua_CFunction) (lua_State *L);
一个 C 函数接受单一的参数 Lua state,返回一个表示返回值个数的数字。所以,函数在将返回值入栈之前不需要清理栈,函数返回之后, Lua 自动的清除栈中返回结果下面的所有内容。
注册接口
void lua_pushcfunction (lua_State *L, lua_CFunction f);
//其定义
#define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0)
//方便接口:
#define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n)))
案例
//定义
static int l_sin (lua_State *L)
{
double d = luaL_checknumber(L, 1);
lua_pushnumber(L, sin(d));
return 1; /* number of results */
}
//注册
lua_pushcfunction(l, l_sin);
lua_setglobal(l, "mysin");
C函数库
Lua 通过注册,就可以看到库中的 C 函数。一旦一个 C 函数被注册之后并保存到 Lua 中,在 Lua 程序中就可以直接引用他的地址(当我们注册这个函数的时候传递给 Lua 的地址)来访问这个函数了。luaL_openlib 函数接受一个 C 函数的列表和他们对应的函数名,并且作为一个库在一个 table 中注册所有这些函数。大致步骤如下:
//1. 定义函数
static int l_dir (lua_State *L)
{
... /* as before */
}
//2.导出声明数组
static const struct luaL_reg mylib [] =
{
{ "dir", l_dir},
{NULL, NULL} /* sentinel */
};
//3. luaL_openlib 声明,注意数组中最后一对必须是{NULL,NULL},用来表示结束
int luaopen_mylib (lua_State *L)
{
luaL_openlib(L, "mylib", mylib, 0);
return 1;
}
//4. lua中加载
mylib = loadlib("fullname-of-your-library", "luaopen_mylib")
字符串操作
当 C 函数接受一个来自 lua 的字符串作为参数时,有两个规则必须遵守:
- 当字符串正在被访问的时候不要将其出栈;
- 永远不要修改字符串。
当 C 函数需要创建一个字符串返回给 lua 的时候:
字符串操作中需要注意的其他:
- 永远不要将指向 Lua 字符串的指针保存到访问他们的外部函数中,因为lua_tostring 返回的是指向内部字符串的内部拷贝指针2. lua_tonumber 返回的字符串结尾总会有一个字符结束标志 0,但是字符串中间也可能包含 0, lua_strlen 返回字符串的实际长度
结束语
函数操作过程中需要注意栈的容量,及时进行清除。函数操作过程中操作更多的是对参数的处理,比如说参数是C定义的类,下篇文章介绍
Lua 与 C 交互值 函数调用(2)的更多相关文章
- Lua和C++交互 学习记录之三:全局值交互
主要内容转载自:子龙山人博客(强烈建议去子龙山人博客完全学习一遍) 部分内容查阅自:<Lua 5.3 参考手册>中文版 译者 云风 制作 Kavcc vs2013+lua-5.3.3 1 ...
- Lua和C++交互详细总结
转自:http://cn.cocos2d-x.org/tutorial/show?id=1474 一.Lua堆栈 要理解Lua和C++交互,首先要理解Lua堆栈. 简单来说,Lua和C/C++语言通信 ...
- 用好lua+unity,让性能飞起来——lua与c#交互篇
前言 在看了uwa之前发布的<Unity项目常见Lua解决方案性能比较>,决定动手写一篇关于lua+unity方案的性能优化文. 整合lua是目前最强大的unity热更新方案,毕竟这是唯一 ...
- [转载]Lua和C++交互详细总结
原文请看:Lua和C++交互详细总结 转自:http://cn.cocos2d-x.org/tutorial/show?id=1474 一.Lua堆栈 要理解Lua和C++交互,首先要理解Lua堆栈. ...
- Lua和C交互的简易教程
转载请标明出处:http://blog.csdn.net/shensky711/article/details/52458051 本文出自: [HansChen的博客] Lua栈 要理解Lua和C++ ...
- Lua与C++交互初探之Lua调用C++
Lua与C++交互初探之Lua调用C++ 上一篇我们已经成功将Lua的运行环境搭建了起来,也成功在C++里调用了Lua函数.今天我来讲解一下如何在Lua里调用C++函数. Lua作为一个轻量级脚本语言 ...
- Lua 和 C 交互中虚拟栈的操作
Lua 和 C 交互中虚拟栈的操作 /* int lua_pcall(lua_State *L, int nargs, int nresults, int msgh) * 以保护模式调用具有" ...
- Lua和C++交互 学习记录之九:在Lua中以面向对象的方式使用C++注册的类
主要内容转载自:子龙山人博客(强烈建议去子龙山人博客完全学习一遍) 部分内容查阅自:<Lua 5.3 参考手册>中文版 译者 云风 制作 Kavcc vs2013+lua-5.3.3 在 ...
- Lua和C++交互 学习记录之八:C++类注册为Lua模块
主要内容转载自:子龙山人博客(强烈建议去子龙山人博客完全学习一遍) 部分内容查阅自:<Lua 5.3 参考手册>中文版 译者 云风 制作 Kavcc vs2013+lua-5.3.3 1 ...
随机推荐
- 动手实现react Modal组件
Modal组件 长话不多说,接下来让我们来动手实现一个react Modal组件. 我们先来看一下实际效果 Modal的布局 首先,让我们先思考下一个Modal组件的布局是怎么样的. 我们先拿一个基本 ...
- python实现定时任务
定时任务的实现方式有很多种,如windows服务,借助其他定时器jenkins运行脚本等方式.本文介绍的是python中的一个轻量级模块schedule. 安装 pip命令:pip install s ...
- 实现text-detection-ctpn一路的坎坎坷坷
小编在学习文字检测,因为作者提供的caffe实现没有训练代码(不过训练代码可以参考faster-rcnn的训练代码),所以我打算先使用tensorflow实现,主要是复现前辈的代码,主要是对文字检测模 ...
- JavaWeb学习 (二十五)————监听器(Listener)
一.监听器介绍 1.1.监听器的概念
- 阿里云 Ubuntu16.04 apache2 ssl证书下载与安装(必须有域名)
阿里云申请免费SSL证书并下载(包含xxx.key|xxx._root_bundle.crt|xxx._public.crt三个文件) 用https是自己的网站收到保护,不易被攻克,所以保护自己的网站 ...
- 动态规划法(八)最大子数组问题(maximum subarray problem)
问题简介 本文将介绍计算机算法中的经典问题--最大子数组问题(maximum subarray problem).所谓的最大子数组问题,指的是:给定一个数组A,寻找A的和最大的非空连续子数组.比如 ...
- Angular Forms - 自定义 ngModel 绑定值的方式
在 Angular 应用中,我们有两种方式来实现表单绑定--"模板驱动表单"与"响应式表单".这两种方式通常能够很好的处理大部分的情况,但是对于一些特殊的表单控 ...
- matlab 的解函数的不同方式
f=@(x)(sin(x)+2*x); f(pi/2) f=sym('sin(x)+2*x'); subs(f,'x',pi/2) %将 g 表达式中的符号变量 s 用 数值 f 替代 f=i ...
- C#设计模式--迭代器模式(学习Learning hard设计模式笔记)
/// <summary> /// 抽象聚合接口 /// </summary> public interface IListCollection { Iterator GetI ...
- HTML5的DeviceOrientation实现微信摇一摇功能
在HTML5中,DeviceOrientation特性所提供的DeviceMotion事件封装了设备的运动传感器时间,通过改时间可以获取设备的运动状态.加速度等数据(另还有deviceOrientat ...