【测试环境】

lua版本: 5.2.1

【问题场景】

在”luaL_dofile”处报错,并且没有任何错误信息。
代码如下:

#ifdef __cplusplus
extern "C" {
#endif
#include "luajit-2.0/lua.h"
#include "luajit-2.0/lualib.h"
#include "luajit-2.0/lauxlib.h"
#ifdef __cplusplus
}
#endif
static lua_State* L;

static int MyLuaInit(const char *data_dir)
{
        int ret=0;
        L = lua_open();
        if (L) {
                char lua_path[512];
                luaL_openlibs(L);           //load Lua base libraries
                sprintf(lua_path, "%s/lua/", data_dir);
                set_lua_path(L, lua_path);
                strcat(lua_path, "test.lua");
                ret = luaL_dofile(L, lua_path);
                if (0==ret) {
                        printf("import lua script success.\n");
                        return -1;
                }
                lua_close(L);
                L = NULL;
        }
        printf("import lua script error, reason: %d.\n", ret);
        return -1;
}

【问题定位】

0x00 查看API手册(传送门

函数: luaL_dofile

函数声明:

int luaL_dofile (lua_State *L, const char *filename);

函数定义:

(luaL_loadfile(L, filename) || lua_pcall(L, 0, LUA_MULTRET, 0))

函数描述: load并run给定的lua脚本文件.如果运行成功返回值为0,失败则为1.

题外话,stackoverflow上有人问lual_dofile(); wont load script with C++ and Lua,答案很简单,题主把luaL_dofile函数错写为luaL_loadfileluaL_loadfile 这个函数只load不运行。

回到正文,这个函数的文档说“我”只能告诉你执行成功或者失败,原因不归我管。跪了。线断了

0x01 查stackoverflow

果不其然,有这个问题的答案。解决办法就是使用:

static void print_error(lua_State *L)
{
        fprintf(stderr, "\nFATAL ERROR:%s\n\n", lua_tostring(L, -1));
        exit(1);
}

问题就此解决,晚上吃鸡。


( ̄▽ ̄)~■干杯□~( ̄▽ ̄)


╮(╯_╰)╭


○| ̄|_


问题还没有解决,不开心。。

为什么用lua_tostring这个函数就能输出error信息,莫非是专门打印error函数?

0x02 再次翻看API手册

函数:lua_tostring
函数声明:

const char *lua_tolstring (lua_State *L, int index, size_t *len);

函数定义:
略(太长了,没有被写入手册)
函数描述: 等价于len=NULL的lua_tolstring。这个函数根据index从栈中取出值,并convert为C string。

也就是说,这个函数是从栈中去出C能打印的字符串的。那么,问题来了,取error信息的时候,index=-1,这能说明什么?说明栈上为-1的位置保存了错误信息,那么这个错误信息是谁推到栈里的?真相只有一个,突然想到luaL_dofile这个函数是由执行两个函数拼出来的。
关键就在于lua_pcall.

0x03 又看API手册

函数:lua_pcall
函数声明:

int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc);

函数定义:

函数描述:

Calls a function in protected mode.

Both nargs and nresults have the same meaning as in lua_call. If there are no errors during the call, lua_pcall behaves exactly like lua_call. However, if there is any error, lua_pcall catches it, pushes a single value on the stack (the error message), and returns an error code. Like lua_call, lua_pcall always removes the function and its arguments from the stack.

If errfunc is 0, then the error message returned on the stack is exactly the original error message. Otherwise, errfunc is the stack index of an error handler function. (In the current implementation, this index cannot be a pseudo-index.) In case of runtime errors, this function will be called with the error message and its return value will be the message returned on the stack by lua_pcall.

Typically, the error handler function is used to add more debug information to the error message, such as a stack traceback. Such information cannot be gathered after the return of lua_pcall, since by then the stack has unwound.

The lua_pcall function returns 0 in case of success or one of the following error codes (defined in lua.h):

LUA_ERRRUN: a runtime error.
LUA_ERRMEM: memory allocation error. For such errors, Lua does not call the error handler function.
LUA_ERRERR: error while running the error handler function.

划重点,if there is any error, lua_pcall catches it, pushes a single value on the stack (the error message), and returns an error code.在执行lua的时候发生错误,则会将错误信息推到栈顶。故,-1的位置可以取到错误信息。

0x04 题外话

这个发现问题其实不难解决,不过引出了一个新的问题。在lua的大部分说明都跟栈有关系,可以看出来c中调用lua跟栈绝对有莫大关系。

要理解Lua和C++交互,首先要理解Lua堆栈。

简单来说,Lua和C/C++语言通信的主要方法是一个无处不在的虚拟栈。栈的特点是先进后出。

在Lua中,Lua堆栈就是一个struct,堆栈索引的方式可是是正数也可以是负数,区别是:正数索引1永远表示栈底,负数索引-1永远表示栈顶。