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);
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现