【问题标题】:Putting Function Pointers in a Perl6 NativeCall CStruct将函数指针放入 Perl6 NativeCall CStruct
【发布时间】:2018-02-13 17:19:57
【问题描述】:

试图与一个 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, &amp;foo-callback) 或类似的,但我不能 似乎是在强迫他们进去。

除了编写一个小 C 函数来获取所有 Perl 6 函数指针并将它们插入 C 中的结构之外,还有其他方法吗?

【问题讨论】:

    标签: raku nativecall


    【解决方案1】:

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

    声明一个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-*

    可能有一种比指针到数字到字符串到数字到指针来回更简单的方法,但现在这可以解决问题。

    【讨论】:

    • 注意 %lld 是 64 位体系结构特定的。如果您有 32 位指针,请使用 %ld。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-08
    • 2012-08-04
    • 1970-01-01
    • 2019-07-13
    • 1970-01-01
    相关资源
    最近更新 更多