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 ...
随机推荐
- Zuul过滤器
1.Zuul过滤器生命周期Zuul大部分功能都是通过过滤器来实现的,Zuul定义了4种标准的过滤器类型,这些过滤器类型对应于请求的典型生命周期.a.pre: 这种过滤器在请求被路由之前调用.可利用这种 ...
- apache log4j打印日志源码出口
Throwable.class: public void printStackTrace(PrintStream s) { synchronized (s) { s.println(this); St ...
- Docker入门之一Docker在Window下安装
最近这几年,各个大公司都在打造自己的云平台,什么阿里云,华为云,腾讯云等等云,以及各种的微服务架构,其实在这当中Docker容器技术算是一个很重要的角色. 一.下载 在下载之前首先检查一下自己的电脑是 ...
- over()的用法
开窗函数over的常用方法-- 1.为每条数据显示聚合信息-- 2.为每条数据提供分组的聚合函数结果-- 3.与排名函数一起使用 -- 1 为每条数据显示聚合信息 -- 准备一些数据-- 该查询表只能 ...
- [PHP] 算法-二位有序数组中查找的PHP实现
在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 1.二 ...
- Java8的lambda表达式和Stream API
一直在用JDK8 ,却从未用过Stream,为了对数组或集合进行一些排序.过滤或数据处理,只会写for循环或者foreach,这就是我曾经的一个写照. 刚开始写写是打基础,但写的多了,各种乏味,非过来 ...
- C code example for strdup
#include <stdlib.h> #include <stdio.h> #include <string.h> #include <malloc.h&g ...
- 通过AccessKey调用阿里云CDN接口刷新CDN资源案例
通过AccessKey远程调用阿里云CDN接口,快速实现自动化集成部署. CdnService.java package com.nfky.cdn; import com.aliyuncs.Defau ...
- ngx-echarts响应式图表
一.代码 html代码 <!-- html --> <nz-card style="background-color: #0e0b2a;border: 0px;color: ...
- vue选中与取消简单实现
<li v-for="(item,index) in assign" :key="index" @click="selected(item)&q ...