10

我该如何进行这项工作?

更新:在搜索了包含 Raku 规范测试的 Github 之后,在这里,我没有找到任何传递 CArray[of-structs] 的示例。 这里有 Christoph 2017 年发表的一篇文章,其中给出了“解决方法”。

Christoph 的解决方案可能有效,但在 NativeCall 中会更好,如果没有更好的办法的话。

在 Github 上有一个使用 a 的 Rakudo 测试,int TakeAStructArray(Struct **structs)如果您可以编写一个 C 函数将其 args 重新打包以转发到 a ,这可能会有所帮助TakeAnArrayOfStruct( struct Struct[])

下面,JJMerelo 对我的怀疑是由于 Rakudo 中的错误而失败。

我有一个C函数,它使用类似于 NativeCall 文档中使用的 timespec 结构:

结构 TS {

int show2( struct TS ts[2] ) { printf("show2: (1) %ld %ld (2) %ld %ld\n", ts[0].ot, ts[0].one, ts[ 1].ot, ts[1].one); 返回0;从C调用时效果很好。

从 Raku (moar) 调用不起作用:

class TS is repr('CStruct') {
    has long $.ot;
    has long $.one;
}

sub show2( CArray[TS] --> int32) is native(
    '/home/rir/Raku/try-CArray/libshow.so'
    ) {*}

my $A = CArray[TS].new;
$A[1] = TS.new( :ot(50), :one(60));
$A[0] = TS.new( :ot(30), :one(40));
show2( $A);
say "  s/b 30 40 50 60\n";

没有错误,结果如下:

show2: (1)  94658691693328 94658695469968  (2) 0 0
  s/b 30 40 50 60

类似的功能int show2long( long i[2] )int showTS(int show1( struct TS *ts )工作。

4

1 回答 1

7

前段时间我遇到了这个确切的问题,这迫使我写了一个解决方法

简短的回答,这在 NativeCall 中尚不支持。

长答案:如上所述,有一种解决方法。如果您不想浏览我的代码,答案可以归结为:

使用Pointer.

或者,更好的是,一个 Buf 然后使用 NativeCall::Blob's pointer-to

然后,您将使用以下例程将元素作为位置访问:

  # Cribbed from MySQL::Native. Thanks, ctilmes!
  method AT-POS(Int $field) {
    nativecast(
      T,
      Pointer.new( $!b + $field * nativesizeof(T) )
    )
  }

以及以下在正确索引处分配结构的方法

  method bind (Int() $pos, T $elem) {
    my uint64 $p = $pos;

    memcpy(
      Pointer.new( $!b + $p * nativesizeof(T) ),
      nativecast(Pointer, $elem),
      nativesizeof(T)
    );
  }

因此,此类事情的基本实现将是:

use NativeHelper::Blob;

class TypedBuffer {
  has Buf $!b;

  submethod BUILD ( :@array-of-structs ) {
    # Assumes that array contains homogeneous struct values!
    $!b = Buf.allocate(
      @array-of-structs.elems * nativesizeof( @a[0].WHAT )
    )
  }    

  method new (@array-of-structs) {
    self.bless( :@array-of-structs); 
  }

  method bind (Int() $pos, T $elem) {
    my uint64 $p = $pos;

    memcpy(
      Pointer.new( $!b + $p * nativesizeof(T) ),
      nativecast(Pointer, $elem),
      nativesizeof(T)
    );
  }

  method AT-POS(Int $field) {
    nativecast(
      T,
      Pointer.new( $!b + $field * nativesizeof(T) )
    )
  }

  method Pointer {
    pointer-to($!b);
  }

}

基本用法是:

my $aos = TypedBuffer.new(@array-of-structs);  # Init
my $struct = $aos[0];                          # Retrieve first element
$aos.bind(2, $new-struct);                     # Replace third element
my-c-func($aos.Pointer);                       # Make call to a C Function
于 2020-11-10T07:21:43.437 回答