在C ++和Lua之间来回发送变量指针?

时间:2010-08-14 03:09:13

标签: c++ scripting variables pointers lua

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

然而,问题是如何从Lua执行C ++函数或方法?或者需要解决方法吗?

如果可能,您是否可以添加一个代码段来向我展示它是如何完成的?

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

3 个答案:

答案 0 :(得分:9)

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

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

考虑具有私有成员名称(c字符串)和年龄(int)的基本人员类。名称由构造函数设置,不能更改。年龄暴露于吸气剂和二传手:

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 init期间创建一个包含这些c函数的元表“Person”。此元表必须与构造函数中的userdata相关联。

// 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

答案 1 :(得分:4)

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

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

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

答案 2 :(得分:2)

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

也许this question也有帮助。