lua_call/lua_pcall/xpcall
vs2013+lua5.3.3
1.涉及函数
主要C函数:lua_call和lua_pcall
主要lua函数xpcall
2.正常使用lua_call
①hello.lua文件内容
function ccall_test_func(val)
print(string.format("ccall_test_func val = %d",val))
end
②C++文件内容(主要内容在test_func函数中的lua_call函数,表示调用lua中的ccall_test_func函数,并将值1传给val)
//这个头文件包含了所需的其它头文件
#include "lua.hpp" //测试函数
void test_func(lua_State* L){
lua_getglobal(L, "ccall_test_func");
lua_pushinteger(L, );
lua_call(L, , );//调用
} static const luaL_Reg lua_reg_libs[] = {
{ "base", luaopen_base },
{ "coroutine", luaopen_coroutine },
{ "table", luaopen_table },
{ "io", luaopen_io },
{ "os", luaopen_os },
{ "string", luaopen_string },
{ "utf8", luaopen_utf8 },
{ "math", luaopen_math },
{ "debug", luaopen_debug },
{ "package", luaopen_package },
{ NULL, NULL }
}; int main(int argc, char* argv[])
{
if (lua_State* L = luaL_newstate()){ //注册让lua使用的库
const luaL_Reg* lua_reg = lua_reg_libs;
for (; lua_reg->func; ++lua_reg){
luaL_requiref(L, lua_reg->name, lua_reg->func, );
lua_pop(L, );
}
//加载脚本,如果出错,则打印错误
if (luaL_dofile(L, "hello.lua")){
std::cout << lua_tostring(L, -) << std::endl;
} test_func(L); //调用测试函数 lua_close(L);
}
else{
std::cout << "luaL_newstate error !" << std::endl;
} system("pause"); return ;
}
③运行后正常输出结果
3.使用lua_call产生的问题
①将lua中文件的ccall_test_func函数修改为抛出一个error,如下:
function ccall_test_func(val)
print(string.format("ccall_test_func val = %d",val)) error("throw error") --新增加一行模拟抛出错误
end
②运行后,直接抛出错误了
4.方法一:使用lua的保护模式函数xpcall处理错误
①将hello.lua文件中的ccall_test_func函数修改为
function ccall_test_func(val)
--将函数调用修改为局部函数
local function lua_test_func(val)
print(string.format("ccall_test_func val = %d",val)) error("throw error") --新增加一行模拟抛出错误
end --调用保护函数xpcall
local status, err_msg = xpcall(
function(v) lua_test_func(v) end, --调用局部函数,v的值由下面的val提供
function(msg) local ret_msg = debug.traceback(msg, ) ret_msg = string.format("xpcall val = %d \n%s", val, ret_msg) return ret_msg end, --结合debug.traceback得到系统内部提供的堆栈信息msg,并将ret_msg作为xpcall的返回值
val) --传给v if not status then
print(err_msg)
end
end
②简化一下
③正常运行效果
5.方法二:使用C++的保护模式函数lua_pcall处理错误
①在hello.lua中增加一个由C++调用的错误处理函数ccall_err_handler
function ccall_test_func(val)
print(string.format("ccall_test_func val = %d",val)) error("throw error") --新增加一行模拟抛出错误
end --增加的C++调用的错误处理函数
function ccall_err_handler(msg)
print(debug.traceback(msg,))
end
②修改C++中的test_func函数,使用保护模式函数lua_pcall
//测试函数
void test_func(lua_State* L){
lua_getglobal(L, "ccall_err_handler");
lua_getglobal(L, "ccall_test_func");
lua_pushinteger(L, );
lua_pcall(L, , , -);//调用ccall_test_func,当出现错误时,会将error msg放在栈顶-1位置让放置在-3位置的错误处理函数ccall_err_handler使用
}
②简化一下
function ccall_test_func(val)
--将函数调用修改为局部函数
local function lua_test_func(val)
print(string.format("ccall_test_func val = %d",val)) error("throw error") --新增加一行模拟抛出错误
end --错误处理函数
local function error_handler(msg)
local ret_msg = debug.traceback(msg, )
ret_msg = string.format("xpcall val = %d \n%s", val, ret_msg)
return ret_msg
end local status, err_msg = xpcall(
lua_test_func, --参数只有后面值val的话,这里可以直接使用函数名
error_handler, --参数只有msg的话(如果有其它传入参数,则需要使用上面的方式),这里可以直接使用函数名
val) --传给val if not satus then
print(err_msg)
end
end
③正常运行效果
6.使用lua_pcall,增加输出用户信息
①从上面能看到,lua_pcall也能处理异常的情况,但是在异常信息里只包含了堆栈信息,没有对用户数据的描述
②修改hello.lua的错误处理函数,增加参数接收val的值
-- 增加的C++调用的错误处理函数
function ccall_err_handler(val, msg)
local err_msg = string.format("ccall_err_handler val = %d \n%s", val, msg) -- 这里使用debug.traceback不起作用,因为栈已经展开,所以收集不到栈跟踪信息了
print(err_msg)
end
③修改一下C++中的test_func函数,如下
//测试函数
void test_func(lua_State* L){
lua_getglobal(L, "ccall_test_func");
lua_pushinteger(L, );
if (lua_pcall(L, , , )){ //如果此时出现错误,则当前-1位置为error msg
lua_getglobal(L, "ccall_err_handler"); //error msg变为-2
lua_pushinteger(L, ); //增加用户数据信息 //error msg变为-2
lua_pushvalue(L, -); //将-3位置的error msg 放置为-1位置
lua_pcall(L, , , );
}
}
④正常运行效果
上面可以看到数据信息以及错误信息了,但是堆栈跟踪信息收集不到了。
综上所述:一般情况下,建议使用方法一,简单方便而且信息全。
以下两点来自于 《Lua 5.3 参考手册》中文版 译者 云风 制作 Kavcc
7.lua_pcall函数介绍
int lua_pcall (lua_State *L, int nargs, int nresults, int msgh);
以保护模式调用一个函数。
nargs 和 nresults 的含义与 lua_call 中的相同。 如果在调用过程中没有发生错误, lua_pcall 的行为和 lua_call 完全一致。 但是,如果有错误发生的话, lua_pcall 会捕获它, 然后把唯一的值(错误消息)压栈,然后返回错误码。 同 lua_call 一样, lua_pcall 总是把函数本身和它的参数从栈上移除。
如果 msgh 是 0 , 返回在栈顶的错误消息就和原始错误消息完全一致。 否则, msgh 就被当成是 错误处理函数 在栈上的索引位置。 (在当前的实现里,这个索引不能是伪索引。) 在发生运行时错误时, 这个函数会被调用而参数就是错误消息。 错误处理函数的返回值将被 lua_pcall 作为错误消息返回在堆栈上。
典型的用法中,错误处理函数被用来给错误消息加上更多的调试信息, 比如栈跟踪信息。 这些信息在 lua_pcall 返回后, 由于栈已经展开,所以收集不到了。
lua_pcall 函数会返回下列常数 (定义在 lua.h 内)中的一个:
LUA_OK (0): 成功。
LUA_ERRRUN: 运行时错误。
LUA_ERRMEM: 内存分配错误。对于这种错,Lua 不会调用错误处理函数。
LUA_ERRERR: 在运行错误处理函数时发生的错误。
LUA_ERRGCMM: 在运行 __gc 元方法时发生的错误。 (这个错误和被调用的函数无关。)
8.关于lua的错误处理
由于 Lua 是一门嵌入式扩展语言,其所有行为均源于宿主程序中 C 代码对某个 Lua 库函数的调用。 (单独使用 Lua 时,lua 程序就是宿主程序。) 所以,在编译或运行 Lua 代码块的过程中,无论何时发生错误, 控制权都返回给宿主,由宿主负责采取恰当的措施(比如打印错误消息)。
可以在 Lua 代码中调用 error 函数来显式地抛出一个错误。 如果你需要在 Lua 中捕获这些错误, 可以使用 pcall 或 xpcall 在 保护模式 下调用一个函数。
无论何时出现错误,都会抛出一个携带错误信息的 错误对象 (错误消息)。 Lua 本身只会为错误生成字符串类型的错误对象, 但你的程序可以为错误生成任何类型的错误对象, 这就看你的 Lua 程序或宿主程序如何处理这些错误对象。
使用 xpcall 或 lua_pcall 时, 你应该提供一个 消息处理函数 用于错误抛出时调用。 该函数需接收原始的错误消息,并返回一个新的错误消息。 它在错误发生后栈尚未展开时调用, 因此可以利用栈来收集更多的信息, 比如通过探知栈来创建一组栈回溯信息。 同时,该处理函数也处于保护模式下,所以该函数内发生的错误会再次触发它(递归)。 如果递归太深,Lua 会终止调用并返回一个合适的消息。
lua_call/lua_pcall/xpcall的更多相关文章
- 理解 Lua 的那些坑爹特性
按:最近看到了依云的文章,一方面,为Lua被人误解而感到十分难过,另一方面,也为我的好友, 依云没有能够体会到Lua的绝妙和优雅之处而感到很遗憾,因此我写了这篇文章,逐条款地说明了 依云理解中出现的一 ...
- Lua和C之间的交互
转自:http://blog.csdn.net/sumoyu/article/details/2592693 (一) Lua 调C函数 什么样类型的函数可以被Lua调用 typedef int ( ...
- Lua的函数调用和协程中,栈的变化情况
Lua的函数调用和协程中,栈的变化情况 1. lua_call / lua_pcall 对于这两个函数,对栈底是没有影响的--调用的时候,参数会被从栈中移除,当函数返 回的时候,其返回值会从函数处 ...
- lua与C交互 具体
什么样类型的函数可以被Lua调用 typedef int (*lua_CFunction) (lua_State *L); 符合类型的函数怎样处理后才可以被Lua调用 使用lua_register或者 ...
- Lua 与 C 交互值 函数调用(2)
@(语言) Lua和C 函数间的使用,都是通过栈来交互,并且基于遵守一定的规则,按照这个规则来就可以了. 1. 调用Lua函数 调用Lua方法过程 将被调用的函数入栈: 依次将所有参数入栈: 使用 l ...
- delphi调用LUA函数来处理一些逻辑
替同事做了个洛奇英雄传自动染色程序,关于屏幕取色的. 因为里面他对颜色的要求比较复杂,改动也比较大,于是我让他把逻辑写在 lua 脚本里面. uses LUA, LUALIB; function lu ...
- lua_pcall,lua_call 调用前后栈情况
lua_pcall和lua_call功能一样,只是lua_pcall提供了一个可以提供错误处理函数的功能 首先压入函数 ,再依次压入参数,现在你就可以调用lua_call了,函数调用后将参数,函数都弹 ...
- lua_pcall与lua_call之间的区别
lua_pcall与lua_call之间的区别 定义: void lua_call (lua_State *L, int nargs, int nresults); int lua_pcall (lu ...
- lua以xpcall实现try/catch功能
-- 打印错误信息 local function __TRACKBACK__(errmsg) ); print("-------------------------------------- ...
随机推荐
- JDK常用命令(二)jstack
Dump Dump文件是进程的内存镜像.可以把程序的执行状态通过调试器保存到dump文件中.Dump文件一般用来给驱动程序编写人员调试驱动程序用的,在java中用来分析正在运行的程序在内存中的堆栈信息 ...
- IIS W3C日志记录字段和HTTP状态代码的说明
像新网的部分服务器ftp目录有这个文件,但是就是提示没权限查看也没有权限下载,还得必须给他们打电话才能要到. 做为网站拥有者,我们应该关注IIS日志,从里面我们不仅仅可以看到网站的访问记录和搜索引擎的 ...
- Bugku-CTF之web基础$_GET
Day3 web基础$_GET http://123.206.87.240:8002/get/ 打开之后是一段代码
- Static变量与代码块
* static:是一个关键字,用于修饰成员变量和成员方法 * static的特点: * 被所有的对象所共享 * 可以使用类名调用 * 静态的加载优先于对象 * 随着类的加载而加载 * static的 ...
- ./configure: error: C compiler cc is not found
没有安装gcc 在安装nginx之前先安装依赖软件 yum install -y gcc gcc-c++ autoconf pcre pcre-devel make automake wget htt ...
- python --- 05 字典 集合
一.字典 可变数据类型 {key:value}形式 查找效率高 key值必须是不可变的数据类型 1.增删改查 1).增 dic["新key"] = "新va ...
- 用js互相调用iframe页面内的js函数
http://www.jb51.net/web/18555.html 1,首先获得右栏iframe对象 var frames=document.getElementById("frameid ...
- C++笔记(2017/2/9)
this指针 this指针作用就是指向成员函数所作用的对象. 非静态成员函数中可以直接使用this来代表指向该函数作用的对象的指针. 静态成员函数中不能使用this指针. 静态成员 static 定义 ...
- 3、Python迭代器、列表解析及生成器(0530)
1.动态语言 sys.getrefcount() //查看对象的引用计数 增加对象的引用计数场景 对象创建时:以赋值的方式,创建变量名的同时就会创建变量 将对象添加进容器时:类似list.app ...
- 【译】第44节---EF6-存储过程映射
原文:http://www.entityframeworktutorial.net/entityframework6/code-first-insert-update-delete-stored-pr ...