C#、C、Lua分别有不同的异常处理机制,在跨语言函数调用的时候,必须要正确的处理异常,否则会导致堆栈错误、内存泄露、程序崩溃等问题。tolua对此做了非常全面的安全处理,值得我们去学习。如果我们要自己去做一些C层面的扩展,也必须要对这些底层原理熟记于心,才能避免各种诡异问题。
本文作者游蓝海,未经许可禁止转载。
C#调用Lua函数
C#调用Lua函数的时候,必须使用lua_pcall
接口进行调用。因为lua_pcall
会拦截C语言层面的异常,确保异常不会破坏掉C#解释器的堆栈。
lua_pcall API说明:
int lua_pcall (lua_State *L, int nargs, int nresults, int error);
参数名称 | 说明 |
---|---|
L | Lua解释器指针 |
nargs | 参数数量 |
nresults | 返回值数量 |
error | 异常处理函数句柄。也就是处理函数在Lua栈上的索引 |
如果函数调用成功,返回0,并且在Lua栈push上nresults个结果(如果实际结果不足,会push nil);否则,返回相应的错误码,并且在Lua栈push上错误原因的字符串。不管是否执行成功,lua_pcall
都会把push的函数和nargs个参数从栈顶清除。
如果指定了错误处理函数,在函数调用失败的时候,Lua会调用该错误处理函数来处理错误原因。通常情况下,我们可以传入debug.traceback
函数,这样可以得到函数调用堆栈。
ToLua在BeginPCall
的时候,会将错误处理函数traceback
和要调用的函数压栈。在PCall
的时候,如果函数调用出错,则向C#层面抛出异常LuaException
。
C# LuaState类部分源码:
// 将错误处理函数和要调用的函数压栈
public int BeginPCall(int reference)
{
return LuaDLL.tolua_beginpcall(L, reference);
}
// 执行函数调用
public void PCall(int args, int oldTop)
{
if