【问题标题】:Sending variable pointers back and forth between C++ and Lua?在 C++ 和 Lua 之间来回发送变量指针?
【发布时间】:2011-03-29 18:04:33
【问题描述】:

我正在寻找一种在 C++ 和 Lua 之间来回传输变量地址的方法。例如,将一个对象从 C++ 传输到 Lua 并进行一些处理,然后将其传输回 C++。

但是,问题是如何从 Lua 中执行 C++ 函数或方法?还是需要解决方法?

如果可能的话,您能否包含一个代码 sn-p 来告诉我它是如何完成的?

我知道我还没有完全理解整个画面,所以如果有什么不对的地方,请纠正我。

【问题讨论】:

  • 请考虑对此给予赏金,也许将问题改写为更整洁。我也想知道答案。
  • Truncheon,你在这件事上成功找到了方法吗?很抱歉没有早点回复,下面给出的答案,我需要抽时间尝试一下,然后考虑选择最佳答案,k?

标签: c++ scripting variables pointers lua


【解决方案1】:

我花了很多时间才让 Lua 与 C++ 类一起工作。 Lua 比 C++ 更像是一个 C 风格的 API,但是有很多方法可以将它与 C++ 一起使用。

在 Lua C API 中,指针由 userdata(或 light userdata 表示,它没有元表且不被垃圾回收)。用户数据可以与一个元表相关联,它的作用有点像 Lua 中的一个类。作为该元表一部分的 C 函数包装了 c++ 类的方法,并在 Lua 中充当该类的方法。

考虑一个具有私有成员名称(一个 c 字符串)和年龄(一个 int)的基本人员类。名称由构造函数设置,不能更改。使用 getter 和 setter 暴露年龄:

class person
{
  private:  
    const char* name;
    int age;
  public:
    person(const char* n) {
        name = strdup(n);
    }
    ~person() {
        free((void*)name);
    }
    void print() {
        printf("%s is %i\n",name, age);
    }
    int getAge() {
        return this->age;
    }
    void setAge(int a) {
        this->age=a;
    }
};

为了首先向 Lua 公开它,我将为所有符合 lua_CFunction 原型的方法编写包装函数,该原型将 lua 状态作为参数并返回一个 int 表示它压入堆栈的值的数量(通常一或零)。

这些函数中最棘手的是构造函数,它将返回一个像对象一样的 Lua 表。为此,lua_newuserdata 用于创建指向对象的指针。我假设我们将在 Lua 初始化期间创建一个包含这些 c 函数的元表“Person”。此元表必须与构造函数中的用户数据相关联。

// wrap the constructor
int L_newPerson(lua_State* L) {
    //pointer to pointer
    person **p = (person **)lua_newuserdata(L, sizeof(person *));
    //pointer to person
    *p = new person(lua_tostring(L, 1)); 
    // associate with Person meta table
    lua_getglobal(L, "Person"); 
    lua_setmetatable(L, -2); 
    return 1;
}

当创建其他方法时,您只需要记住第一个参数将始终是指向我们使用 newPerson 创建的指针的指针。要从中获取 C++ 对象,我们只需取消引用 lua_touserdata(L, 1); 的返回值。

int L_print(lua_State* L) {
    person** p = (person**) lua_touserdata(L, 1);
    (*p)->print();
    return 0;
}

int L_getAge(lua_State* L) {
    person** p = (person**) lua_touserdata(L, 1);
    lua_pushnumber(L, (*p)->getAge());
    return 1;
}

int L_setAge(lua_State* L) {
    person** p = (person**) lua_touserdata(L, 1);
    (*p)->setAge(lua_tonumber(L, 2));
    return 0;
}

最后在 Lua 的初始化过程中使用 luaL_register 建立了 Person 元表。

// our methods...
static const luaL_Reg p_methods[] = {
    {"new", L_newPerson},{"print", L_print},
    {"getAge", L_getAge},{"setAge", L_setAge}, 
    {NULL, NULL}
};

lua_State* initLuaWithPerson() {
    lua_State* L=lua_open();
    luaL_openlibs(L);
    luaL_register(L, "Person", p_methods);  
    lua_pushvalue(L,-1);
    lua_setfield(L, -2, "__index"); 
    return L;
}

并进行测试...

const char* Lua_script = 
    "p1=Person.new('Angie'); p1:setAge(25);"
    "p2=Person.new('Steve'); p2:setAge(32);"
    "p1:print(); p2:print();";

int main() {
    lua_State* L=initLuaWithPerson();
    luaL_loadstring(L, Lua_script);
    lua_pcall(L, 0, 0, 0);
    return 0;
}

在 Lua 中还有其他实现 OO 的方法。本文介绍了替代方案: http://loadcode.blogspot.com/2007/02/wrapping-c-classes-in-lua.html

【讨论】:

  • 为什么 L_print ,L_getAgeL_setAge 这些函数的第一个参数是 person ?这是lua函数将self作为第一个参数传递的原因吗?很抱歉评论晚了
  • @liu - 是的,这正是它的工作原理。冒号语法基本上意味着第一个参数是 self 并且允许您以对习惯于 OO 的人来说更自然的方式编写对象方法。
【解决方案2】:

请参阅 Lua 用户 wiki 上有关 binding code to Lua 的文章。有几种技术可以使 C++ 对象从栅栏的 Lua 一侧变得有用,其复杂性范围从让 Lua 持有一个它不能直接使用的不透明指针,到完全包装暴露所有 C++ 方法,甚至可能允许使用 Lua 编写的方法扩展对象。

对于用 C 编写的简单函数库,使用 Lua API 手动编写自己的绑定非常容易,以便在 Lua 堆栈和库函数之间移动。

对于基于对象的系统,手工完成的工作量要大得多,因此该页面上列出的绑定工具之一将使您的生活更轻松。

【讨论】:

    【解决方案3】:

    我不确定这是否是您正在寻找的,但您尝试过吗 luabind?

    也许this question 也有帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-10-27
      • 1970-01-01
      • 1970-01-01
      • 2016-05-03
      • 2013-02-08
      • 1970-01-01
      • 2013-09-10
      相关资源
      最近更新 更多