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 ...
随机推荐
- cropper实现图片剪切上传
一.引入文件 <script src="jquery.min.js"></script> <link rel="stylesheet&quo ...
- 交换路由中期测验20181226(动态路由配置与重分发、NAT转换、ACL访问控制列表)
测试拓扑: 接口配置信息 HostName 接口 IP地址 网关 Server 0 Fa0 172.16.15.1/24 172.16.15.254 Server 1 Fa0 100.2.15.200 ...
- Redis 内存模型
了解 Redis 的 5 种对象类型(字符串.哈希.列表.集合.有序集合)的用法和特点的基础,了解 Redis 的内存模型,对 Redis 的使用有很大帮助,例如: 估算 Redis 内存使用量.内存 ...
- 一篇极好的Git 总结
欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由腾讯工蜂发表于云+社区专栏 常用命令 简单的,常用的命令也就几个.但是想非常熟练使用,怕是要记住几十个. Workspace:工作区( ...
- js-ES6学习笔记-const命令
1.const声明一个只读的常量.一旦声明,常量的值就不能改变. 2.const声明的变量不得改变值,这意味着,const一旦声明变量,就必须立即初始化,不能留到以后赋值. 3.const的作用域与l ...
- DML和索引内部结构变化
1.修改数据对索引结构的影响 合适的索引对查询性能和效率的提升是巨大的,但是万事有利有弊,拥有索引的表在增.删.改记录时需要去维护索引.如何让增.删.改更快速更高效?这就需要了解数据修改时对索引结构会 ...
- Spring之IOC容器
在前面博客中介绍什么是依赖注入时有提到:依赖注入是组件之间依赖关系由容器在运行期决定,即由容器动态的将某个依赖关系注入到组件之中.那什么是容器?既然Spring框架实现了IOC,那Spring中的容器 ...
- C++ 输入、输出运算符重载
C++ 能够使用流提取运算符 >> 和流插入运算符 << 来输入和输出内置的数据类型.我们可以重载流提取运算符和流插入运算符来操作对象等用户自定义的数据类型. 在这里,有一点很 ...
- cookie和session的区别和用法
1. 由于HTTP协议是无状态的协议,所以服务端需要记录用户的状态时,就需要用某种机制来识具体的用户,这个机制就是Session.典型的场景比如购物车,当你点击下单按钮时,由于HTTP协议无状态,所以 ...
- Spring Boot 1.5.* 升级 2.1 - 完善中
Spring Boot 原版本 1.5.12.RELEASE 新版本 2.1.0.RELEASE Spring Cloud 原版本 Edgware.SR3 新版本 Finchley.SR2 一.Act ...