调用 Lua 函数从 C:最小示例导致 LUA_ERRRUN。

huangapple go评论72阅读模式
英文:

Calling Lua Function from C: Minimal example results in LUA_ERRRUN

问题

我想从C中调用一个外部的lua_5.2函数,所以我创建了一个最小的示例来尝试。

最小的测试文件:

--- 文件名: play.lua
function hello()
    print("Hello World!\n")
end

尝试从C中调用这个函数:

#include <stdio.h>
#include <stdlib.h>

#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"


int
main(void) {
    lua_State *L;
    int status;
    int result;

    L = luaL_newstate();
    luaL_openlibs(L);

    status = luaL_loadfile(L, "play.lua");
    if (status != LUA_OK) {
        fprintf(stderr, "无法加载 'play.lua'!");
        exit(1);
    }

    lua_getglobal(L, "hello");
    if (lua_isfunction(L, -1)) {
        fprintf(stderr, "错误:不是一个函数!\n");
        exit(1);
    }

    result = lua_pcall(L, 0, 0, 0);
    if (result != LUA_OK) {
        fprintf(stderr, "运行lua时出错:%i\n", result);
        exit(1);
    }
    fprintf(stdout, "lua运行正常\n");
    lua_pop(L, lua_gettop(L));

    lua_close(L);
    return 0;
}

然而,调用该可执行文件会导致LUA_ERRRUN (2) 错误:

运行lua时出错:2

我不太确定我在这里做错了什么,文档对我来说有点模糊不清 - 根据5.2参考手册,我正在正确使用pcall(零参数和零返回值的函数),而且我显然正确地从堆栈中获取了函数(否则之前的错误将会显示)。

你有任何关于我做错了什么的想法吗?

英文:

I want to call an external lua_5.2 function from C, so I made a minimal example to try it out.

The minimal testfile:

--- filename: play.lua
function hello()
	print(&quot;Hello World!\n&quot;)
end

Trying to call this function from C:

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;

#include &quot;lua.h&quot;
#include &quot;lualib.h&quot;
#include &quot;lauxlib.h&quot;


int
main(void) {
    lua_State *L;
    int status;
    int result;

    L = luaL_newstate();
    luaL_openlibs(L);

    status = luaL_loadfile(L, &quot;play.lua&quot;);
    if (status != LUA_OK) {
        fprintf(stderr, &quot;Could not load &#39;play.lua&#39;!&quot;);
        exit(1);
    }

    lua_getglobal(L, &quot;hello&quot;);
    if (lua_isfunction(L, -1)) {
        fprintf(stderr, &quot;ERROR: Not a function!\n&quot;);
        exit(1);
    }

    result = lua_pcall(L, 0, 0, 0);
    if (result!= LUA_OK) {
        fprintf(sterr, &quot;Error running lua: %i\n&quot;, result);
        exit(1);
    }
    fprintf(stdout, &quot;lua ran fine\n&quot;);
    lua_pop(L, lua_gettop(L));

    lua_close(L);
    return 0;
}

Calling that executable results however in LUA_ERRUN (2)

Error running lua: 2

I am not quite sure what I am doing wrong here, and the documentation is a little bit opaque to me -- according to the 5.2 reference manual I am using pcall correctly (function with zero args and zero return vals), and I apparently grabbed the function from the stack correctly (otherwise they earlier error would have shown).

Any idea what I am doing wrong?

答案1

得分: 2

lua_pcall的返回值不是 LUA_OK时,错误消息将被推送到堆栈顶部。

可以使用lua_tostring等函数来操作此值以在C中使用。

result = lua_pcall(L, 0, 0, 0);

if (result != LUA_OK) {
    fprintf(stderr, "Error running lua: %s\n", lua_tostring(L, -1));
    exit(1);
}

您还可以使用lua_error(L)传播错误,但这可能会违反受保护的调用的目的。

执行此操作会显示错误消息

Error running lua: attempt to call a nil value

这意味着 lua_getglobal(L, "hello"); 推送了 nil 到堆栈上。

请注意,我们之所以能够进行到这一步,是因为 if (lua_isfunction(L, -1)) 是用于检查的相反条件。

全局变量 hello 的值是 nil,因为包含其定义的从未被执行过。也就是说,luaL_loadfile(最终是lua_load)只是 加载 块,而不会执行它们。

加载块后,可以像执行任何其他函数一样执行它(lua_call等)。

例如:

#include <stdio.h>
#include <stdlib.h>

#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"

int
main(void) {
    lua_State *L = luaL_newstate();

    luaL_openlibs(L);

    int status;
    int result;

    status = luaL_loadfile(L, "play.lua"); /* 加载块 */
    if (status != LUA_OK) {
        fprintf(stderr, "Could not load 'play.lua': %s\n", lua_tostring(L, -1));
        exit(1);
    }

    result = lua_pcall(L, 0, 0, 0); /* 执行块 */
    if (result != LUA_OK) {
        fprintf(stderr, "Error running lua: %s\n", lua_tostring(L, -1));
        exit(1);
    }

    lua_getglobal(L, "hello");
    if (!lua_isfunction(L, -1)) {
        fprintf(stderr, "ERROR: Not a function!\n");
        exit(1);
    }

    result = lua_pcall(L, 0, 0, 0);
    if (result != LUA_OK) {
        fprintf(stderr, "Error running lua: %s\n", lua_tostring(L, -1));
        exit(1);
    }

    puts("lua ran fine");
    lua_close(L);
}

输出:

Hello World!

lua ran fine

请注意,luaL_dofile是一个宏,定义如下:

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

这是一种方便的加载和执行块的方式。

英文:

When the return value of lua_pcall is not LUA_OK, an error message will have been pushed onto the top of the stack.

This value can be manipulated with functions like lua_tostring for use in C.

result = lua_pcall(L, 0, 0, 0);

if (result != LUA_OK) {
    fprintf(stderr, &quot;Error running lua: %s\n&quot;, lua_tostring(L, -1));
    exit(1);
}

(You can also propagate the error with lua_error(L), but that may defeat the purpose of the protected call.)

Doing this reveals the error

Error running lua: attempt to call a nil value

which means lua_getglobal(L, &quot;hello&quot;); pushed nil onto the stack.

(Note that we only get this far because if (lua_isfunction(L, -1)) is the inverse condition to check for.)

The value of the global variable hello is nil because the chunk containing its definition was never executed. That is, luaL_loadfile (ultimately lua_load) only loads chunks, it does not execute them.

After loading a chunk, you may execute it like any other function (lua_call, etc.).

For example:

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;

#include &quot;lua.h&quot;
#include &quot;lualib.h&quot;
#include &quot;lauxlib.h&quot;

int
main(void) {
	lua_State *L = luaL_newstate();

	luaL_openlibs(L);

	int status;
	int result;

	status = luaL_loadfile(L, &quot;play.lua&quot;); /* load the chunk */
	if (status != LUA_OK) {
		fprintf(stderr, &quot;Could not load &#39;play.lua&#39;: %s\n&quot;, lua_tostring(L, -1));
		exit(1);
	}

	result = lua_pcall(L, 0, 0, 0); /* execute the chunk */
	if (result != LUA_OK) {
		fprintf(stderr, &quot;Error running lua: %s\n&quot;, lua_tostring(L, -1));
		exit(1);
	}

	lua_getglobal(L, &quot;hello&quot;);
	if (!lua_isfunction(L, -1)) {
		fprintf(stderr, &quot;ERROR: Not a function!\n&quot;);
		exit(1);
	}

	result = lua_pcall(L, 0, 0, 0);
	if (result != LUA_OK) {
		fprintf(stderr, &quot;Error running lua: %s\n&quot;, lua_tostring(L, -1));
		exit(1);
	}

	puts(&quot;lua ran fine&quot;);
	lua_close(L);
}

Output:

Hello World!

lua ran fine

Note that luaL_dofile is a macro defined as

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

and is a convenient way to load and execute a chunk.

huangapple
  • 本文由 发表于 2023年7月3日 22:12:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/76605585.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定