如何从Lua脚本调用C ++函数?

时间:2009-07-30 22:25:46

标签: c++ visual-c++ lua

我正在使用Visual Studio 2005。

------------------------ [luapassing.cpp] ------------------ -

#include "lua.h"
static int myCfunc (Lua_State *L){
   double trouble = lua_tonumber(L,1);
   lua_pushnumber(L,16.0 -trouble);
   return 1;
}
int luaopen_luapassing (Lua_State *L){
   static const lua_reg Map [] = {{"dothis",myCfunc},{NULL,NULL}};
   luaL_register(L,"cstuff",Map);
   return;
}

------------------------- [csample.lua] ----------------- --------

package.cpath = "./CLua2.dll"
require "luapassing"

print("hola")
print(seth.doThis(120))

3 个答案:

答案 0 :(得分:5)

我看到几个问题。我将描述它们,并提供一个代码片段,应该可以正常工作,因为我相信你希望这个样本能够工作。

你的第一个问题是C ++编译器破坏了从你的DLL导出的唯一函数的名称,其名称对Lua来说很重要:luaopen_luapassing()。 Windows的库存二进制分发版编译为C程序,并假定DLL模块入口点的C样式名称。

此外,您对luaopen_x功能的协议略有错误。该函数返回一个整数,告诉Lua Lua堆栈顶部有多少项是Lua使用的返回值。 require假定的协议更喜欢将新模块的表对象保留在堆栈顶部并将其返回给Lua。为此,luaopen_x函数通常会使用luaL_register(),然后返回1.

还有命名问题。用纯Lua编写的模块有机会不太了解它们的名字。但是用C编写的模块必须从DLL中导出一个函数,该函数名称中包含模块名称。他们还必须将该模块名称提供给luaL_register(),以便在全局环境中创建和更新正确的表。最后,客户端Lua脚本将在名为传递给require的名称的全局表中看到已加载的模块,该表也从require返回,以便它可以缓存在该脚本的本地中。

使用C代码的其他几个问题是数字类型确实应该拼写为lua_Number以便于移植,并且使用luaL_checknumber()而不是lua_tonumber()是常规的强制执行函数所需的参数。就个人而言,我会将一个名为与其名称相关的公共函数的C实现命名为Lua公开,但这只是一个品味问题。

此版本的C端应解决这些问题:

#include "lua.h"
static int my_dothis (Lua_State *L){
   lua_Number trouble = luaL_checknumber(L,1);
   lua_pushnumber(L,16.0 -trouble);
   return 1;
}
extern "C" int luaopen_luapassing (Lua_State *L){
    static const lua_reg Map [] = {
        {"dothis", my_dothis},
        {NULL,NULL}
    };
    luaL_register(L,"luapassing",Map);
    return 1;
}

然后,示例脚本需要通过其正确的名称引用加载的模块,并通过其正确的名称引用该模块定义的函数。 Lua区分大小写,因此如果模块创建名为dothis()的函数,则脚本必须使用相同的名称,并且例如找不到名为doThis()的名称。

require "luapassing"

print("hola")
print(luapassing.dothis(120))

我应该补充一点,我实际上并没有编译并运行上面的内容,因此可能会有一两个错误或者两个作为练习; - )

答案 1 :(得分:3)

如果您要进行大量的C ++到lua绑定,您可能需要查看luabind

答案 2 :(得分:2)

如果您要编译为C ++并希望匹配“C”接口,则应将外部可见函数声明为extern "C"以避免名称损坏。