Lua luaopen_io 调用失败(转)

转自 http://wangjunle23.blog.163.com/blog/static/117838171201122233310573/

 

当我练习这一部分的时候,发现了一个问题——直接调用luaopen_io会使C程序crash。我使用VC++ 2005编译C代码,使用由lua-5.1.4生成的DLL。

    我查了Lua5.1参考手册,上面有几处涉及到了这个问题:

    To have access to these libraries, the C host program should call the luaL_openlibs function, which opens all standard libraries. Alternatively, it can open them individually by calling luaopen_base(for the basic library), ... and luaopen_debug (for the debug library). These functions are declared in  lualib.h and should not be called directly: you must call them like any other Lua C function, e.g., by using lua_call. 

        ...

        The luaopen_* functions (to open libraries) cannot be called directly, like a regular C function. They must be called through Lua, like a Lua function.

    大体意思就是说,你不能直接调用luaopen_*这些用来打开标准库的函数,你必须通过Lua来调用它们,比如使用lua_call。

    没有具体例子。那就靠自己琢磨了。

    之后我尝试用lua_pcall来修改对luaopen_io的直接调用,方法如下:

    lua_getglobal(L, "luaopen_io");

    lua_pcall(L, 0, 0, 0);

    但是结果令我很失望,lua_pcall返回2,即LUA_ERRRUN:运行时错误。

    然后我又尝试使用lua_cpcall,方法如下:

    lua_cpcall(L, luaopen_io, NULL);

    让人欣喜的是,它可以顺利运行。

    我不满足于现状,又翻出源码来看。在lua-5.1.4的源码中,linit.c这个文件里实现了luaL_openlibs这个函数,具体如下:

    static const luaL_Reg lualibs[] = {      

 {"", luaopen_base},       

{LUA_LOADLIBNAME, luaopen_package},      

{LUA_TABLIBNAME, luaopen_table},      

{LUA_IOLIBNAME, luaopen_io},      

{LUA_OSLIBNAME, luaopen_os},      

{LUA_STRLIBNAME, luaopen_string},      

{LUA_MATHLIBNAME, luaopen_math},      

{LUA_DBLIBNAME, luaopen_debug},      

{NULL, NULL}     };

 

    LUALIB_API void luaL_openlibs (lua_State *L)

{

      const luaL_Reg *lib = lualibs;      

for (; lib->func; lib++) {        

lua_pushcfunction(L, lib->func);        

lua_pushstring(L, lib->name);        

lua_call(L, 1, 0);       }    

}

    有源码,自然一切一目了然。

使用lua_call来间接调用luaopen_*的方法就是彩色字体显示的,

先将函数压栈,再将参数(库的名字)压栈,

最后调用lua_call(一个参数,0个返回值)。

 

首先,官方文档里面提到不要直接调用luaopen_*这些函数,那么就不要直接调用了。
不能直接调用的原因,我也不清楚。表面看来就是liolib.c中的luaopen_io函数的实现里调用了三个newfenv和一个lua_setfenv,它们创建并设置了新的环境。但是为什么新的环境就使程序crash了呢?以我现在的能力还无法给出解释。 使用lua_call、lua_pcall、lua_cpcall来间接调用这些函数。
具体3种方法:

      1. lua_cpcall(L, luaopen_io, NULL);

      2. lua_pushcfunction(L, luaopen_io);          lua_pushstring(L, LUA_IOLIBNAME);          lua_pcall(L, 1, 0, 0);      

      3. lua_pushcfunction(L, luaopen_io);          lua_pushstring(L, LUA_IOLIBNAME);          lua_call(L, 1, 0);

 

posted @ 2014-12-03 14:14  曦花  阅读(2960)  评论(0)    收藏  举报