lua C API

来源:互联网 发布:哪个网站有卖淘宝小号 编辑:程序博客网 时间:2024/05/16 12:44

1:   lua_pcall   、  lua_call   、   lua_cpcall

与lua_call相对应的是lua_pcall函数,lua_pcall会以保护模式调用栈中的函数。以保护模式调用意思是,当被调用的函数发生任何错误时,该错误不会传播,不像lua_call会把错误传递到上一层(发生longjmp调用),lua_pcall所调用的栈中函数发生错误时,lua_pcall会捕捉这个错误,并向栈中压入一个错误信息,并返回一个错误码。在应用程序中编写主函数时,应该使用lua_pcall来调用栈中的函数,捕获所有错误。而在为Lua编写扩展的C函数时,应该调用lua_call,把错误返回到脚本层。

lua_cpcall和lua_pcall类似,都是在应用程序中编写主函数时使用,都会捕获错误,向栈中压入一个错误信息,并返回一个错误码;只不过lua_cpcall调用的是c函数.参考luaproc项目。

在lua的世界里, 什么是保护模式和非保护模式呢?这个问题得从Lua错误处理方式说起,c语言对程序里出现的异常错误处理方式是

使用了setjmp和longjmp两个非局部跳转函数来处理。setjmp函数用来设置异常错误发生时,程序的返回点,类似于try;longjmp函数用于

抛出异常错误,类似于throw。在lapi.c文件里查看lua_call和lua_pcall两个API的实现发现:lua_call会调用longjmp, lua_pcall不调用

longjmp;lua_pcall在错误发生时的处理方式是给虚拟栈压入错误信息,并将lua解释器封固在一致的状态。lua_call在错误发生时,会调用

longjmp抛出异常,然后程序跳转到lua解释器的setjmp出,lua解释器捕获错误。所以在为Lua编写c函数库时,应该使用lua_call ;而在编写

应用程序的主函数时,使用lua_pcall。

static void openlibs( lua_State *L ) { 
    lua_cpcall( L, luaopen_base, NULL );
    lua_cpcall( L, luaopen_package, NULL );
    registerlib( L, "io", luaopen_io );
    registerlib( L, "os", luaopen_os );
    registerlib( L, "table", luaopen_table );
    registerlib( L, "string", luaopen_string );
    registerlib( L, "math", luaopen_math );
    registerlib( L, "debug", luaopen_debug );
}

2:   lua_error  、 luaL_error、  lua_atpanic   

这三个API是用于在c/c++处理lua错误

每一个C程序都有他自己的错勿处理方式,当你打算为Lua写一个库函数的时候,这里有一些标准的处理错误的方法可以参考。不论什么时候,C函数发现错误只要简单的调用lua_error(或者luaL_error,后者更好,因为她调用了前者并格式化了错误信息)。Lua_error函数会清理所有在Lua中需要被清理的,然后和错误信息一起回到最初的执行lua_pcall的地方。具体如何使用可以参考rings库

c/c++在处理lua错误分两种情形:

第一:应用程序中的错误处理,分两种,设置panic函数或者使用lua_pcall调用

典型的情况是应用的代码运行在非保护模式下。由于应用的代码不是被Lua调用的,Lua根据上下文情况来捕捉错误的发生(也就是说,Lua

能调用setjmp)。在这些情况下,当Lua遇到像 "not enough memory" 的错误,他不知道如何处理。他只能调用一个panic函数退出应用。(你可以

使用lua_atpanic函数设置你自己的panic函数)

在错误发生时,如果你不想你的应用退出,即使在内存分配失败的情况下,你必须在保护模式下运行你的代码。大部分或者所有你的Lua代码

通过调用lua_pcall来运行,所以,它运行在保护模式下。即使在内存分配失败的情况下,lua_pcall也返回一个错误代码,使得lua解释器处于和谐

的(consistent)状态。如果你也想保护所有你的与Lua交互的C代码,你可以使用lua_cpcall

第二:库中的错误处理

当你打算为Lua写一个库函数的时候,这里有一些标准的处理错误的方法可以参考。不论什么时候,C函数发现错误只要简单

的调用lua_error(或者luaL_error,后者更好,因为她调用了前者并格式化了错误信息)。Lua_error函数会清理所有在Lua中需要被清理

的,然后和错误信息一起回到最初的执行lua_pcall的地方

3: lua_getfield  、lua_gettable

lua_getfield(L, -1, key)  于以下两行的效果一样

lua_pushstring(L, key);

lua_gettable(L, -1)


4: lua_setfield  、  lua_settable

lua_pushstring(L, key)

lua_pushnumber(L, value)

lua_settable(L, -3)

以上三行的效果等同于以下两行

lua_pushnumber(L, value)

lua_setfield(L, -2, key)


5:lua_setglobal   、lua_getglobal  

static int l_sin (lua_State *L) {

    double d = lua_tonumber(L, 1);  /* get argument */

    lua_pushnumber(L, sin(d));      /* push result */

    return 1;                       /* number of results */

}

lua_pushcfunction(l, l_sin); /*将类型为fC函数的值l_sin入栈 */

lua_setglobal(l, "mysin");  /* 将C函数l_sin赋值给lua全局变量mysin */


比如lua配置文件有如下lua函数

function func(x, y)

    return (x^2 * math.sin(y))/(1 - x)

end

那么可以在c中调用lua函数func

     lua_getglobal(L, "func");   /* function to be called */

    lua_pushnumber(L, 1,);    /* push 1st argument */

    lua_pushnumber(L, 2);    /* push 2nd argument */

   lua_pcall(L, 2, 1, 0) != 0)


6:lua_isXXXX  、lua_toXXX  、  luaL_checkXXX、 lua_type、lua_typename

lua_is*函数来检查一个元素是否是一个指定的类型,*可以是任何Lua类型。lua_isnumberlua_isstring函数不检查这个值是否是指定的类型,而是看它是否能被转换成指定的那种类型。例如,任何数字类型都满足lua_isstring

为了从栈中获得值,这里有lua_to*函数:

int           lua_toboolean (lua_State *L, int index);

double        lua_tonumber (lua_State *L, int index);

const char *  lua_tostring (lua_State *L, int index);

size_t        lua_strlen (lua_State *L, int index);

即使给定的元素的类型不正确,调用上面这些函数也没有什么问题。在这种情况下,lua_toboolean、lua_tonumber和lua_strlen返回0,其他函数返回NULL。由于ANSI C没有提供有效的可以用来判断错误发生数字值,所以返回的0是没有什么用处的。对于其他函数而言,我们一般不需要使用对应的lua_is*函数:我们只需要调用lua_is*,测试返回结果是否为NULL即可。

Lua_tostring函数返回一个指向字符串的内部拷贝的指针。你不能修改它(使你想起那里有一个const)。只要这个指针对应的值还在栈内,Lua会保证这个指针一直有效。当一个C函数返回后,Lua会清理他的栈,所以,有一个原则:永远不要将指向Lua字符串的指针保存到访问他们的外部函数中。

   辅助库中的luaL_checkXXX函数可以检查参数类型是否正确,如果类型不正确,它会抛出一个错误消息,反之,返回该类型的值。

lua_type函数,它返回栈中元素的类型。(lua_is*中的有些函数实际上是用了这个函数定义的宏)在lua.h头文件中,每种类型都被定义为一个常量:LUA_TNILLUA_TBOOLEANLUA_TNUMBERLUA_TSTRINGLUA_TTABLELUA_TFUNCTIONLUA_TUSERDATA以及LUA_TTHREAD


7:lua_rawget、lua_rawset、lua_rawgeti、lua_rawseti

出于性能考虑,即绕过元表metatable; 为数组操作提供了lua_rawgeti,luarawseti两个C API函数。

void lua_rawgeti (lua_State *L, int index, int key);

void lua_rawseti (lua_State *L, int index, int key);


index指向table在栈中的位置;key指向元素在table中的位置。


8:luaL_checkXXX、luaL_checkany

luaL_checkXXX类函数用于错误判断,判断lua传递给C的数据是否合法,如果非法会抛出错误。常规的c编程中,错误判断往往是if(xxx) errorLog(...)方式处理,而在lua于C交互的时候,是使用luaL_checkXXX判断。






0 0
原创粉丝点击