Typedefs(类型定义),Ruby和SWIG

4
我正在尝试为一些C++类生成Ruby包装器。生成成功,所有方法都已创建,但问题在于很多C++方法使用了this关键字:
#ifdef USE_LONGLONG_COUNTS
typedef unsigned long long Count;   /* a count of something */
#else
typedef unsigned long Count;        /* a count of something */
#endif

当我在irb中运行一个返回计数的方法时,会得到类似于这样的结果:
irb(main):006:0> ngram.numNgrams(0)
=> #<SWIG::TYPE_p_Count:0x00000001c52280>

我期望获得一个数字... 我尝试使用反射来查看是否能以某种方式获取该值,但没有成功。有什么建议吗?


也许这个链接会有帮助:http://www.swig.org/Doc1.3/SWIG.html#SWIG_nn20 - dimakura
2个回答

2
typedef 的作用是防止 SWIG 确定 Counter 是一种可以直接转换的非盒式类型。如果没有其他信息,SWIG 将按照库中函数的要求将 Counter 视为抽象对象类型,只能由这些函数生产和消费。
您需要告诉 SWIG,Counter 等效于内在的 long 或 long long。
typemap 是 SWIG 实现这一目标的方式。此外,SWIG 语言本身提供了 typedef 来说明 Counter 和其基础内在类型的等效性。
以下是它的工作原理。您应该可以轻松将其转换为解决问题的方案:
// hacking.i
%module hacking
%{
// "Simulation" of the header included verbatim in the glue code.
#ifdef USE_LONGLONG_COUNTS
typedef unsigned long long Count;   /* a count of something */
#else
typedef unsigned long Count;        /* a count of something */
#endif
Count foo(Count count) { return count; }
%}

// The typemaps...
%typemap(in) Count n {
#ifdef USE_LONGLONG_COUNTS
 $1 = ULL2INT($input);
#else
 $1 = ULONG2INT($input);
#endif
}

%typemap(out) Count {
#ifdef USE_LONGLONG_COUNTS
 $result = ULL2NUM($1);
#else
 $result = ULONG2NUM($1);
#endif
}

// Now tell SWIG about the type equivalences and function prototype.
#ifdef USE_LONGLONG_COUNTS
typedef unsigned long long Count;   /* a count of something */
#else
typedef unsigned long Count;        /* a count of something */
#endif
Count foo(Count count);

请注意,如果定义了USE_LONGLONG_COUNTS,则您使用的Ruby必须支持long long类型。并非所有版本都支持。
Typemaps非常强大,有许多选项。您没有提供足够的信息来更具体地解决您的问题。引用Ruby SWIG文档是唯一可能的方法,直到您提供更多信息。
现在进行构建,创建一个文件:
# extconf.rb
require 'mkmf'
create_makefile('hacking')

如果你需要使用unsigned long,则省略-DUSE_LONGLONGCOUNTS

$ swig -c++ -DUSE_LONGLONG_COUNTS -ruby -o wrap.cpp hacking.i
$ ruby extconf.rb
$ make
compiling wrap.cpp
linking shared-object hacking.bundle
$ make install
/usr/bin/install -c -m 0755 hacking.bundle ...  
$ irb
2.2.1 :001 > require 'hacking'
 => true 
2.2.1 :002 > Hacking.foo(1234567890123454567)
 => 1234567890123454567 

1

这很奇怪。

你确定swig“看到”了你对Counttypedef吗?否则,Count只是swig不知道的一些类型,它将其包装为C对象的指针,在这种情况下,swig应该生成警告。

无论如何,我刚刚根据你的问题创建了一个示例,并使用swig 3.0.7测试了它,对我来说它按预期工作(无需typemaps):

dummy.i(取消注释#define USE_LONGLONG_COUNTS以进行其他操作)

%module dummy

%inline %{

#define USE_LONGLONG_COUNTS

#ifdef USE_LONGLONG_COUNTS
typedef unsigned long long Count;   /* a count of something */
#else
typedef unsigned long Count;        /* a count of something */
#endif

Count returnCount(Count count) { return count; }

%}

extconf.rb

require 'mkmf'
create_makefile('dummy')

编译并运行Ruby,我执行以下操作:

swig -c++ -ruby dummy.i
ruby extconf.rb
make
irb

然后在 irb 中,我可以执行以下操作:
irb(main):001:0> require_relative 'dummy'
=> true
irb(main):002:0> Dummy.returnCount(2**64-1)
=> 18446744073709551615
irb(main):003:0> Dummy.returnCount(-1)
=> 18446744073709551615
irb(main):004:0> Dummy.returnCount(2**64)
TypeError: Expected argument 0 of type Count, but got Bignum 18446744073709551616
in SWIG method 'returnCount'
from (irb):4:in `returnCount'
from (irb):4
from /usr/bin/irb:12:in `<main>'

请注意,我的系统/编译器上unsigned long longunsigned long都是64位的,并且我的Ruby版本支持它们。也许如果这不是真的,转换可能无法正常工作,我不知道。

无论如何,另一个答案中声称导致问题的不是typedef


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接