尝试与C库接口,该库带有一个结构,其中包含一系列指向它在不同点调用的函数的指针。
类似的东西:
struct callbacks {
int (*foo)(int);
int (*bar)(int);
}
int set_callbacks(callbacks *cbs);
我可以回复:
sub foo-callback(int32 --> int32) {...}
sub bar-callback(int32 --> int32) {...}
如果这样做会很酷:
class Callbacks is repr<CStruct>
{
has &.foo (int32 --> int32);
has &.bar (int32 --> int32);
}
但它没有。我试图做一些事情:
class Callbacks is repr<CStruct>
{
has Pointer $.foo;
has Pointer $.bar;
}
并将其设置为nativecast(Pointer, &foo-callback)
或其他一些,但我不能
似乎迫使他们在那里。
除了编写一个带有所有Perl 6函数指针并将它们插入C结构中的C函数之外,还有什么方法可以做到这一点吗?
答案 0 :(得分:4)
我仍然无法找到正式的方法来做到这一点,但我想出了解决办法。
声明一个sprintf
的版本,它接受一个正确类型的函数指针(所以它会正确设置调用shim),但是作弊并让sprintf把指针作为一个数字给我({{ 1}})我可以在指针中填充。
%lld
如果您有多个具有不同签名的回调,只需为您需要的每个C调用签名声明class Callbacks is repr<CStruct>
{
has Pointer $.foo;
has Pointer $.bar;
sub sprintf(Blob, Str, & (int32 --> int32) --> int32) is native {}
submethod BUILD(:&foo, :&bar)
{
my $buf = buf8.allocate(20);
my $len = sprintf($buf, "%lld", &foo);
$!foo := Pointer.new($buf.subbuf(^$len).decode.Int);
$len = sprintf($buf, "%lld", &bar);
$!bar := Pointer.new($buf.subbuf(^$len).decode.Int);
}
}
sub foo-callback(int32 $x --> int32) {...}
sub bar-callback(int32 $x --> int32) {...}
my $callbacks = Callbacks.new(foo => &foo-callback,
bar => &bar-callback);
,例如:
sprintf
并为您需要的每个回调指针调用右sub sprintf-ii(Blob, Str, & (int32 --> int32) --> int32)
is native is symbol('sprintf') {}
sub sprintf-isi(Blob, Str, & (int32, Str --> int32) --> int32)
is native is symbol('sprintf') {}
。
可能有一种比使用指向数字的指针来回转换为数字到指针更简单的方法,但现在这样做。