如何在C++中将userdata从一个Lua块传递到另一个Lua块

Zac*_*Lee 1 c++ lua swig lua-userdata

我试图userdatachunk AC++中的Lua脚本()(通过我的示例中的函数返回的变量)获取然后,然后从C++(通过我的示例中的函数参数)将其传递userdata回Lua脚本(chunk B),以便userdata可以chunk B像在原来一样使用chunk A.

MyBindings.h

class Vec2
{
public:
    Vec2():x(0), y(0){};
    Vec2(float x, float y):x(x), y(y){};
    float x, y;
};
Run Code Online (Sandbox Code Playgroud)

MyBindings.i

%module my
%{
    #include "MyBindings.h"
%}

%include "MyBindings.h"
Run Code Online (Sandbox Code Playgroud)

main.cpp

#include <iostream>
#include <lua.hpp>

extern "C"
{
    int luaopen_my(lua_State *L);
}

int main()
{
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);
    luaopen_my(L);
    lua_settop(L, 0);
    /* chunk A */
    luaL_dostring(L, "local vec2 = my.Vec2(3, 4)\n"
                     "function setup()\n"
                       "return vec2\n"
                     "end\n");
    /* chunk B */
    luaL_dostring(L, "function test(p)\n"
                       "print(p.x)\n"
                     "end\n");
    void *userDataPtr = nullptr;

    /* call setup function */
    int top = lua_gettop(L);
    lua_getglobal(L, "setup");
    if (lua_pcall(L, 0, LUA_MULTRET, 0))
    {
        std::cout << lua_tostring(L, -1) << '\n';
        lua_pop(L, 1);
    }
    /* check the return value */
    if (lua_gettop(L) - top)
    {
        /* store userdata to a pointer */
        if (lua_isuserdata(L, -1))
            userDataPtr = lua_touserdata(L, -1);
    }
    /* check if userDataPtr is valid */
    if (userDataPtr != nullptr)
    {
        /* call test function */
        lua_getglobal(L, "test");
        lua_pushlightuserdata(L, userDataPtr); /* pass userdata as an argument */
        if (lua_pcall(L, 1, 0, 0))
        {
            std::cout << lua_tostring(L, -1) << '\n';
            lua_pop(L, 1);
        }
    }
    lua_close(L);
}
Run Code Online (Sandbox Code Playgroud)

结果我得到:

[string"local vec2 = my.Vec2(3,4)..."]:6:尝试索引userdata值(本地'p')

我期望的结果:

3

是否有可能获得userdata来自chunk A然后通过这个来chunk B,因此它可以被用来就像是在chunk A

Vla*_*lad 6

当您获得指向userdata数据的原始指针并将其作为lightuserdata推送到参数时,您将丢失有关该对象类型的所有信息.lightuserdata甚至没有单独的元表.

正确的方法是按原样传递Lua值.将原始返回值保留在Lua堆栈上,或将其复制到其他Lua容器(您的Lua表中用于临时表或Lua注册表),然后将该值复制到Lua堆栈以将其作为参数传递.这样您就不必了解绑定实现.您甚至不必关心这是用户数据还是任何其他Lua类型.

根据您的代码,这可能如下所示:

#include <iostream>
#include <lua.hpp>

extern "C"
{
    int luaopen_my(lua_State *L);
}

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

    /* chunk A */
    luaL_dostring(L, "local vec2 = {x=3, y=4}\n"
                     "function setup()\n"
                       "return vec2\n"
                     "end\n");
    /* chunk B */
    luaL_dostring(L, "function test(p)\n"
                       "print(p.x)\n"
                     "end\n");

    /* call setup function */
    int top = lua_gettop(L);
    lua_getglobal(L, "setup");

    if (lua_pcall(L, 0, LUA_MULTRET, 0))
    {
        std::cout << lua_tostring(L, -1) << '\n';
        lua_pop(L, 1);

        exit(EXIT_FAILURE); // simpy fail for demo
    }

    /* check the return value */
    if (lua_gettop(L) - top)
    {
        // the top now contains the value returned from setup()

        /* call test function */
        lua_getglobal(L, "test");

        // copy the original value as argument
        lua_pushvalue(L, -2);

        if (lua_pcall(L, 1, 0, 0))
        {
            std::cout << lua_tostring(L, -1) << '\n';
            lua_pop(L, 1);
            exit(EXIT_FAILURE);
        }

         // drop the original value
        lua_pop(L, 1);

    }else
    {
        // nothing is returned, nothing to do
    }
    lua_close(L);
}
Run Code Online (Sandbox Code Playgroud)