云风的博文《Lua C API 的正确用法》读后总结
2016-04-07 18:22
615 查看
云风的博文《Lua C API 的正确用法》(http://blog.codingnow.com/2015/05/lua_c_api.html)
该文章是一年前写的,不好意思在原文下面写心得体会了,就把想说的写在这里。
1,在你的程序中嵌入lua时,最好使用由你的编译器编译lua源代码得到的库文件(lua.lib)。
这是因为,在lua的异常处理机制里面会使用一些宏,在不同的编译环境下这些宏有不同的定义,例如:
2,在你的代码中使用lua API时,由于lua API有抛出异常的可能,会导致“抛出异常处”的后面的代码不能执行到。例如:
对于这样的临时内存块,有一个解决办法是使用 lua_newuserdata 来申请一段由lua维护的内存块,它会被GC操作回收掉。例如:
3,lua API函数可能会抛出异常,这些异常应该由 lua_pcall 或者 lua_resume 来捕获,所以要确保lua API函数的调用处于某次 lua_pcall 或者 lua_resume 中。
下面是最常见的创建lua环境的代码,但是这段代码就是有风险的,因为 luaL_openlibs(L) 有可能抛出异常,但是没有捕获异常:
lua官方的解释器的程序源码,就为我们示范了这种正确的做法:
该文章是一年前写的,不好意思在原文下面写心得体会了,就把想说的写在这里。
1,在你的程序中嵌入lua时,最好使用由你的编译器编译lua源代码得到的库文件(lua.lib)。
这是因为,在lua的异常处理机制里面会使用一些宏,在不同的编译环境下这些宏有不同的定义,例如:
#if defined(__cplusplus) /* C++ exceptions */ #define LUAI_THROW(L,c) throw(c) #define LUAI_TRY(L,c,a) try { a } catch(...) \ { if ((c)->status == 0) (c)->status = -1; } #define luai_jmpbuf int /* dummy variable */ #elif defined(LUA_USE_ULONGJMP) /* in Unix, try _longjmp/_setjmp (more efficient) */ #define LUAI_THROW(L,c) _longjmp((c)->b, 1) #define LUAI_TRY(L,c,a) if (_setjmp((c)->b) == 0) { a } #define luai_jmpbuf jmp_buf #else /* default handling with long jumps */ #define LUAI_THROW(L,c) longjmp((c)->b, 1) #define LUAI_TRY(L,c,a) if (setjmp((c)->b) == 0) { a } #define luai_jmpbuf jmp_buf #endif如果你的程序是C++编写的,但是链接的却是在C环境下编译出来的lua.lib,那么表面上工作正常,但是一涉及到异常处理,就会出现很多未知的问题。
2,在你的代码中使用lua API时,由于lua API有抛出异常的可能,会导致“抛出异常处”的后面的代码不能执行到。例如:
struct foobar { const char *a; const char *b; } foobar* pObj = new foobar; pObj->a = lua_tostring(L, 1); pObj->b = lua_tostring(L, 2); ... delete pObj;如果在执行lua_tostring()时抛出了异常,那么后面的 “delete pObj;" 就不能执行到,造成内存泄漏。
对于这样的临时内存块,有一个解决办法是使用 lua_newuserdata 来申请一段由lua维护的内存块,它会被GC操作回收掉。例如:
foobar* pObj = lua_newuserdata(L, sizeof(foobar)); pObj->a = lua_tostring(L, 1); pObj->b = lua_tostring(L, 2);上面的代码有另外一个潜在问题,pObj对象没有初始化,一旦执行lua_tostring()时抛出了异常,就会使得 pObj->a 或者 pObj->b 的值是未初始化的,不管是在宿主代码中访问pObj对象,还是在lua脚本中访问pObj对象,都可能带来未知的问题。正确的写法是这样:
foobar* pObj = lua_newuserdata(L, sizeof(foobar)); pObj->a = NULL; //首先做初始化 pObj->b = NULL; pObj->a = lua_tostring(L, 1); pObj->b = lua_tostring(L, 2);
3,lua API函数可能会抛出异常,这些异常应该由 lua_pcall 或者 lua_resume 来捕获,所以要确保lua API函数的调用处于某次 lua_pcall 或者 lua_resume 中。
下面是最常见的创建lua环境的代码,但是这段代码就是有风险的,因为 luaL_openlibs(L) 有可能抛出异常,但是没有捕获异常:
lua_State *L = luaL_newstate(); if (L) { luaL_openlibs(L); }正确的做法是,把你的代码写到一个 lua_CFunction 中,然后用 lua_pcall 来调用它。而 lua_CFunction 中需要使用的参数,则应该用 void * 通过 lua_pushlightuserdata 来传递。
lua官方的解释器的程序源码,就为我们示范了这种正确的做法:
//辅助函数 static int pmain (lua_State *L) { int argc = (int)lua_tointeger(L, 1); char **argv = (char **)lua_touserdata(L, 2); ... luaL_openlibs(L); /* open standard libraries */ ... }
//主函数 int main (int argc, char **argv) { int status, result; lua_State *L = luaL_newstate(); /* create state */ lua_pushcfunction(L, &pmain); /* to call 'pmain' in protected mode */ lua_pushinteger(L, argc); /* 1st argument */ lua_pushlightuserdata(L, argv); /* 2nd argument */ status = lua_pcall(L, 2, 1, 0); /* do the call */ result = lua_toboolean(L, -1); /* get result */ ... }
相关文章推荐
- evaluateScript--evaluatePopoverScript--区别
- Lua学习笔记-9.4章-非抢占式的多线程
- Lua学习笔记六——package
- LUA require 搜索路径指定方法
- ngx_lua访问数据库
- lua使用table.concat连接大量字符串
- lua探索--------------(_G相关)
- LuaSQLite3 搭建使用过程
- Lua学习教程之 可变參数数据打包与解包
- Programming in Lua
- 我和Lua并非一见钟情,我们期待着日久生情(相遇篇)
- Embedding LuaJIT in 30 minutes (or so)
- FFI Library (lua 调用 c)
- Lua求n的阶乘
- Lua协同程序
- 使用ngx_lua构建高并发应用(2)
- 使用ngx_lua构建高并发应用(1)
- lua 调用c 函数
- 传说中的 oltp.lua 脚本
- 由javascarp入门lua