LUA通过C语言运行时的错误处理机制分析

 

在用C语言调用LUA脚本引擎时,必须对脚本的错误进行识别和处理

1.错误类型

LUA错误共有以下5种,分别对应的是5个宏定义:

view plaincopy to clipboardprint?
#define LUA_YIELD   1//线程被挂起 
#define LUA_ERRRUN  2//运行时错误 
#define LUA_ERRSYNTAX   3//编译错误 
#define LUA_ERRMEM  4//内存分配错误 
#define LUA_ERRERR  5//在运行错误处理函数时发生的错误 
#define LUA_YIELD 1//线程被挂起
#define LUA_ERRRUN 2//运行时错误
#define LUA_ERRSYNTAX 3//编译错误
#define LUA_ERRMEM 4//内存分配错误
#define LUA_ERRERR 5//在运行错误处理函数时发生的错误
大体上可以分文两种错误即运行时错误和编译时错误

2.错误返回方式

无论是运行时错误还是编译时错误,都将错误信息返回到堆栈的最顶层,可以通过如下代码打印具体的错误信息

view plaincopy to clipboardprint?
const char* error = lua_tostring(L, -1);//打印错误结果 
printf("%s",error); 
lua_pop(L, 1);  
const char* error = lua_tostring(L, -1);//打印错误结果
printf("%s",error);
lua_pop(L, 1); 
3.需要在哪些函数使用后加入错误分析机制

   LUA脚本引擎的使用大致上可以分文两步(这里不包含初始化过程)

    第一步是脚本加载:如下的一些函数

view plaincopy to clipboardprint?
int luaL_loadbuffer (lua_State *L, 
                     const char *buff, 
                     size_t sz, 
                     const char *name); 
int luaL_loadfile (lua_State *L, const char *filename); 
int luaL_loadstring (lua_State *L, const char *s); 
/*实际上这些函数都是对int lua_load (lua_State *L,
              lua_Reader reader,
              void *data,
              const char *chunkname);的封装
*/ 
int luaL_loadbuffer (lua_State *L,
                     const char *buff,
                     size_t sz,
                     const char *name);
int luaL_loadfile (lua_State *L, const char *filename);
int luaL_loadstring (lua_State *L, const char *s);
/*实际上这些函数都是对int lua_load (lua_State *L,
              lua_Reader reader,
              void *data,
              const char *chunkname);的封装
*/
这些函数产生的都是编译时错误,即通过这些函数的返回值只能返回编译时错误

第二步是脚本执行,如下的一些函数

view plaincopy to clipboardprint?
lua_pcall (lua_State *L, int nargs, int nresults, int errfunc); 
lua_pcall (lua_State *L, int nargs, int nresults, int errfunc);
通过该函数返回的是运行时错误

而像其他的一些如下函数,多是步一,步二的组合函数,本身流程并没有改变,这些函数大致如下

view plaincopy to clipboardprint?
int luaL_dostring (lua_State *L, const char *str); 
int luaL_dofile (lua_State *L, const char *filename); 
int luaL_dostring (lua_State *L, const char *str);
int luaL_dofile (lua_State *L, const char *filename);
可以查看帮助文档

4.错误处理示例

如下代码展示了如何对错误处理信息进行处理及打印出出错信息

view plaincopy to clipboardprint?
#include "stdafx.h" 
extern "C" { 
#include "lua.h" 
#include "lualib.h" 
#include "lauxlib.h" 

void PrintLuaError(lua_State* L,int sErr) 

    if (sErr==0) 
    { 
        return; 
    } 
    const char* error; 
    char sErrorType[256]={0}; 
    switch(sErr) 
    { 
    case LUA_ERRSYNTAX://编译时错误 
        /*const char *buf = "mylib.myfun()2222";类似这行语句可以引起编译时错误*/ 
        sprintf_s(sErrorType,sizeof(sErrorType),"%s","syntax error during pre-compilation"); 
        break; 
    case LUA_ERRMEM://内存错误 
        sprintf_s(sErrorType,sizeof(sErrorType),"%s","memory allocation error"); 
        break; 
    case LUA_ERRRUN://运行时错误 
        /*const char *buf = "my222lib.myfun()";类似这行语句可以引起运行时错误,my222lib实际上不存在这样的库,返回的值是nil*/ 
        sprintf_s(sErrorType,sizeof(sErrorType),"%s","a runtime error"); 
        break; 
    case LUA_YIELD://线程被挂起错误 
        sprintf_s(sErrorType,sizeof(sErrorType),"%s","Thread has Suspended"); 
        break; 
    case LUA_ERRERR://在进行错误处理时发生错误 
        sprintf_s(sErrorType,sizeof(sErrorType),"%s","error while running the error handler function"); 
        break; 
    default: 
        break; 
    } 
    error = lua_tostring(L, -1);//打印错误结果 
    printf("%s:%s",sErrorType,error); 
    lua_pop(L, 1);  

int main() 

    lua_State *L = luaL_newstate(); 
    luaL_openlibs(L); 
    const char *buf = "mylib.myfun()";//注意调用规则 
    int s = luaL_loadstring(L, buf);//只是对代码进行解析并不执行 
    const char* error; 
    if ( s==0 ) 
    { 
        s = lua_pcall(L, 0, LUA_MULTRET, 0); 
        if (s!=0) 
        { 
            PrintLuaError(L,s); 
        } 
    } 
    else 
    { 
        PrintLuaError(L,s); 
    } 
    lua_close(L); 
    getchar(); 
    return 0; 

#include "stdafx.h"
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}
void PrintLuaError(lua_State* L,int sErr)
{
 if (sErr==0)
 {
  return;
 }
 const char* error;
 char sErrorType[256]={0};
 switch(sErr)
 {
 case LUA_ERRSYNTAX://编译时错误
  /*const char *buf = "mylib.myfun()2222";类似这行语句可以引起编译时错误*/
  sprintf_s(sErrorType,sizeof(sErrorType),"%s","syntax error during pre-compilation");
  break;
 case LUA_ERRMEM://内存错误
  sprintf_s(sErrorType,sizeof(sErrorType),"%s","memory allocation error");
  break;
 case LUA_ERRRUN://运行时错误
  /*const char *buf = "my222lib.myfun()";类似这行语句可以引起运行时错误,my222lib实际上不存在这样的库,返回的值是nil*/
  sprintf_s(sErrorType,sizeof(sErrorType),"%s","a runtime error");
  break;
 case LUA_YIELD://线程被挂起错误
  sprintf_s(sErrorType,sizeof(sErrorType),"%s","Thread has Suspended");
  break;
 case LUA_ERRERR://在进行错误处理时发生错误
  sprintf_s(sErrorType,sizeof(sErrorType),"%s","error while running the error handler function");
  break;
 default:
  break;
 }
 error = lua_tostring(L, -1);//打印错误结果
 printf("%s:%s",sErrorType,error);
 lua_pop(L, 1);
}
int main()
{
 lua_State *L = luaL_newstate();
 luaL_openlibs(L);
 const char *buf = "mylib.myfun()";//注意调用规则
 int s = luaL_loadstring(L, buf);//只是对代码进行解析并不执行
 const char* error;
 if ( s==0 )
 {
  s = lua_pcall(L, 0, LUA_MULTRET, 0);
  if (s!=0)
  {
   PrintLuaError(L,s);
  }
 }
 else
 {
  PrintLuaError(L,s);
 }
 lua_close(L);
 getchar();
 return 0;
}
 
7。错误的清除

可以通过int lua_error (lua_State *L);进行,该语句执行一个跳转指令,默认情况下是退出程序即 exit(EXIT_FAILURE);

也可以自己定义跳转函数,这一部分暂时还没有深入研究