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的更多相关文章

  1. 理解 Lua 的那些坑爹特性

    按:最近看到了依云的文章,一方面,为Lua被人误解而感到十分难过,另一方面,也为我的好友, 依云没有能够体会到Lua的绝妙和优雅之处而感到很遗憾,因此我写了这篇文章,逐条款地说明了 依云理解中出现的一 ...

  2. Lua和C之间的交互

    转自:http://blog.csdn.net/sumoyu/article/details/2592693 (一) Lua 调C函数 什么样类型的函数可以被Lua调用   typedef int ( ...

  3. Lua的函数调用和协程中,栈的变化情况

    Lua的函数调用和协程中,栈的变化情况 1. lua_call / lua_pcall   对于这两个函数,对栈底是没有影响的--调用的时候,参数会被从栈中移除,当函数返 回的时候,其返回值会从函数处 ...

  4. lua与C交互 具体

    什么样类型的函数可以被Lua调用 typedef int (*lua_CFunction) (lua_State *L); 符合类型的函数怎样处理后才可以被Lua调用 使用lua_register或者 ...

  5. Lua 与 C 交互值 函数调用(2)

    @(语言) Lua和C 函数间的使用,都是通过栈来交互,并且基于遵守一定的规则,按照这个规则来就可以了. 1. 调用Lua函数 调用Lua方法过程 将被调用的函数入栈: 依次将所有参数入栈: 使用 l ...

  6. delphi调用LUA函数来处理一些逻辑

    替同事做了个洛奇英雄传自动染色程序,关于屏幕取色的. 因为里面他对颜色的要求比较复杂,改动也比较大,于是我让他把逻辑写在 lua 脚本里面. uses LUA, LUALIB; function lu ...

  7. lua_pcall,lua_call 调用前后栈情况

    lua_pcall和lua_call功能一样,只是lua_pcall提供了一个可以提供错误处理函数的功能 首先压入函数 ,再依次压入参数,现在你就可以调用lua_call了,函数调用后将参数,函数都弹 ...

  8. lua_pcall与lua_call之间的区别

    lua_pcall与lua_call之间的区别 定义: void lua_call (lua_State *L, int nargs, int nresults); int lua_pcall (lu ...

  9. lua以xpcall实现try/catch功能

    -- 打印错误信息 local function __TRACKBACK__(errmsg) ); print("-------------------------------------- ...

随机推荐

  1. 一键PHP/JAVA安装工具

    OneinStack是一键PHP/JAVA安装脚本工具,包含lnmp,lamp,lnmpa,ltmp,lnmh,MySQL,PostgreSQL,MongoDB等 建议使用 PHP7.1+MYSQL5 ...

  2. opencv学习之路(15)、形态学其他操作(开、闭、顶帽、黑帽、形态学梯度)

    一.形态学其他操作(用的不多,如果忘了也可以通过膨胀腐蚀得到相同效果) 1.开运算 2.闭运算 3.形态学梯度 4.顶帽 5.黑帽 #include "opencv2/opencv.hpp& ...

  3. centos7 update docker

    yum erase docker docker-common docker-client docker-compose -y 编辑一个docker镜像源 vim /etc/yum.repos.d/do ...

  4. PyCharm笔记之搭建Python开发环境

    新建一个空helloworld项目,然后新建一个main.py文件: 此时还无法运行,因为没有配置项目的入口脚本,通过下图的步骤指定一个: 在scrip框里填入你的入口脚本 之后就可以点击绿色的播放按 ...

  5. 封装QML能访问的类

    一.常用宏 1.信号与槽 C++类中的信号与槽都可以在QML中访问 2.C++类的成员函数,Q_INVOKABLE Q_INVOKABLE void function(); 3.C++类的枚举,Q_E ...

  6. How to install Maven on Windows

    To install Apache Maven on Windows, you just need to download the Maven’s zip file, and Unzip it to ...

  7. FireMonkey 源码学习(2)

    三.TControl FireMonkey重写了TControl的代码,实现了众多接口,如下图: 基类上实现了众多功能,这里不详细描述. 四.TEdit 编辑框是从TControl—TStyledCo ...

  8. error和exception有什么区别?

    Error(错误)表示系统级的错误和程序不必处理的异常,是java运行环境中的内部错误或者硬件问题.比如:内存资源不足等.对于这种错误,程序基本无能为力,除了退出运行外别无选择,它是由Java虚拟机抛 ...

  9. Flutter基础用法解析

    解析开始 Flutter中一切皆widget,一切皆组件.学习Flutter中,必须首先了解Flutter的widget.先从最基本的MaterialApp和Scaffold开始了解 1 Materi ...

  10. Run tomcat on port 80 not 8080

    How to run Tomcat on Port 80 A standard Tomcat installation starts the webserver on port 8080 – whic ...