使用SWIG在C和Lua模块之间共享数据指针
2016-11-22 11:5:51
收藏:0
阅读:93
评论:1
我需要向主程序提供数据结构指针,其中我定义了Lua状态,以将由使用SWIG包装的C++代码创建的动态加载Lua模块。
这是我的代码示例:
在SimpleStruct.h中:
#pragma once
struct SimpleStruct
{
int a;
double b;
};
在exmaple.h(这个是使用SWIG编译成Lua库)中:
#pragma once
#include "SimpleStruct.h"
#include <iostream>
class TestClass
{
public:
TestClass()
{
std::cout<<"TestClass created"<<std::endl;
}
~TestClass() {}
void ReadSimpleStruct(void * tmp)
{
std::cout<<"reading pointer: "<<std::endl;
SimpleStruct * pp = reinterpret_cast< SimpleStruct * >(tmp);
std::cout<<"Simple Struct: " << pp->a << " " << pp->b << std::endl;
}
};
仅在example.cpp中:
#include "example.h"
这是我的主程序(LuaTest.cpp):
extern "C"
{
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
}
#include <iostream>
#include "SimpleStruct.h"
int main(int argc, char ** argv)
{
lua_State * L = luaL_newstate();
luaL_openlibs(L);
SimpleStruct * ss = new SimpleStruct();
ss->a = 1;
ss->b = 2;
lua_pushlightuserdata(L,ss);
lua_setglobal( L, "myptr");
int s = luaL_dostring(L, "require('example')");
s = luaL_dostring(L, "mc = example.TestClass()");
s = luaL_dostring(L, "mc:ReadSimpleStruct(myptr)");
if(s)
{
printf("Error: %s \n", lua_tostring(L, -1));
lua_pop(L, 1);
}
lua_close(L);
std::cout<<"done"<<std::endl;
return 0;
}
example.i(从SWIG的Lua示例中复制):
/* File : example.i */
%module example
%{
#include "example.h"
%}
/* Let's just grab the original header file here */
%include "example.h"
我编译所有内容如下:
swig -c++ -lua example.i
g++ -c -fpic example.cpp example_wrap.cxx -I/usr/local/include -I/usr/include/lua5.2/
g++ -shared example.o example_wrap.o -o example.so
g++ LuaTest.cpp -o luatest -llua5.2 -I/usr/include/lua5.2/ -Wall
在Ubuntu 16.04上(在OSX上,路径不同且结果相同)。
在Lua脚本的最后一行,我得到了分段错误(当我尝试在"mc:ReadSimpleStruct(myptr)"中访问pp->a时)。
所以我的问题是:如何使用Lua轻型用户数据向加载的Lua库提供C++对象指针?
一般来说:我在我的主程序中有一个具有游戏参数和对象的类,并且我想将该类的指针提供给使用SWIG编译的其他加载的Lua库。
原文链接 https://stackoverflow.com/questions/40683578
点赞
评论区的留言会收到邮件通知哦~
推荐文章
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?
- addEventListener 返回 nil Lua
- Lua中获取用户配置主目录的跨平台方法
- 如何编写 Lua 模式将字符串(嵌套数组)转换为真正的数组?
使用调试器(或在
TestClass::ReadSimpleStruct
中打印一些额外信息)可以很快地看到段错误的表面原因。在我的测试环境中,tmp
参数的值为0x20
。显然这不对,但要理解为什么错了以及如何修复需要更深入的调查。作为起点,我添加了一个调用
luaL_dostring(L, "print(myptr)")
,并使用调试器检查全局变量是否按预期工作。为了保险起见,我在每次调用luaL_dostring
后添加了一些断言语句,因为实际上你只检查了最后一个的返回值,但这在这里并没有真正产生影响。由于我一生中并没有写过太多 Lua,我查看了 ‘Light userdata’ 的文档,我看到你在使用它,但不知道它是什么。它听起来很理想:
但问题是,如果我们检查生成的 example_wrap.cxx 文件,我们会发现 SWIG 实际上试图比这更聪明一些,如果我们在通过
(arg1)->ReadSimpleStruct(arg2)
生成的调用之前跟踪arg2
的代码,我们会发现它正在调用SWIG_ConvertPtr
(最终调用SWIG_Lua_ConvertPtr
),然后执行以下操作:lua_touserdata(L, index); //...宏定义的一些类型相关处理 *ptr=usr->ptr; // BOOM!
也就是说,你正在做的不是 SWIG 希望看到的
void*
,SWIG 希望通过其类型系统管理它们作为其他函数的返回值或 SWIG 管理的全局变量。(我稍微惊讶 SWIG 让这种情况导致了段错误却没有引发错误,但我认为这是因为void*
在某种程度上被特别处理了)这个旧问题提供了一个很好的例子,以确认我的理解
lua_pushlightuserdata
。基本上,我们需要编写自己的类型映射,以便让此函数参数以你试图使用的方式进行处理(如果你确实不想让 SWIG 管理它)。我们要做的事情非常简单。这里的用例也与我链接的示例非常相似,只不过我们调用lua_touserdata
时所需的变量是一个函数参数。这意味着它在堆栈中的一个正偏移,而不是负偏移。事实上,SWIG 可以用$input
替换告诉我们在类型映射中的偏移量,因此我们的类型映射不仅适用于成员函数的第一个参数。因此,我们在修改后的 example.i 文件内的任何函数参数
void* tmp
中执行此操作的类型映射如下:%module example %{ #include "example.h" %} %typemap(in) void * tmp %{ $1 = lua_touserdata(L, $input); %} %include "example.h"
然后我们可以使用以下命令进行编译和运行:
swig -c++ -lua example.i g++ -fPIC example_wrap.cxx -I/usr/local/include -I/usr/include/lua5.2/ -shared -o example.so && g++ -Wall -Wextra LuaTest.cpp -o luatest -llua5.2 -I/usr/include/lua5.2/ ./luatest TestClass created userdata: 0x11d0730 reading pointer: 0x11d0730 Simple Struct: 1 2 done