首页 文章

将函数指针放在Perl6 NativeCall CStruct中

提问于
浏览
3

试图与一个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函数之外,还有什么方法可以做到这一点吗?

1 回答

  • 4

    我仍然无法找到正式的方法来做到这一点,但我想出了一个解决方法 .

    声明一个版本的 sprintf ,它接受一个正确类型的函数指针(因此它将正确设置调用填充程序),但作弊并让sprintf只是给我一个数字指针( %lld )我可以在指针中填充 .

    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);
    

    如果你有多个具有不同签名的回调,只需为你需要的每个C调用签名声明一个 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') {}
    

    并为您需要的每个回调指针调用右 sprintf-* .

    可能有一种比使用指向数字的指针来回转换为数字到指针更简单的方法,但这就是现在的诀窍 .

相关问题