我如何使这项工作?
更新:在搜索包括 Raku 规范测试在内的 Github 之后,我还没有找到任何传递 CArray[of-structs] 的示例。 这里有克里斯托夫在 2017 年发表的一篇文章,给出了一个“解决方法”。
Christoph 的解决方案可能有效,但如果没有更好的方法,在 NativeCall 中会更好。
在 Github 上有一个使用 a 的 Rakudo 测试,int TakeAStructArray(Struct **structs)如果您可以编写一个 C 函数来重新打包其 args 以转发到 a ,这可能会有所帮助TakeAnArrayOfStruct( struct Struct[])。
下面,JJMerelo 秒我怀疑由于 Rakudo 中的错误而失败。
我有一个C函数,它使用类似于 NativeCall 文档中使用的 timespec 结构:
结构体{
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";
Run Code Online (Sandbox Code Playgroud)
没有错误,只是结果如下:
show2: (1) 94658691693328 94658695469968 (2) 0 0
s/b 30 40 50 60
Run Code Online (Sandbox Code Playgroud)
类似的功能int show2long( long i[2] )
和int showTS(int show1( struct TS *ts )工作。
不久前我遇到了这个确切的问题,这迫使我编写了一个解决方法
简短的回答,这在 NativeCall 中尚不支持。
长答案:如上所述,有一个解决方法。如果你不想浏览我的代码,答案归结为:
使用一个Pointer.
或者,更好的是,一个 Buf 然后使用 NativeCall::Blob 的pointer-to.
然后,您将使用以下例程将元素作为位置访问:
# Cribbed from MySQL::Native. Thanks, ctilmes!
method AT-POS(Int $field) {
nativecast(
T,
Pointer.new( $!b + $field * nativesizeof(T) )
)
}
Run Code Online (Sandbox Code Playgroud)
以及在适当的索引处分配结构的以下方法
method bind (Int() $pos, T $elem) {
my uint64 $p = $pos;
memcpy(
Pointer.new( $!b + $p * nativesizeof(T) ),
nativecast(Pointer, $elem),
nativesizeof(T)
);
}
Run Code Online (Sandbox Code Playgroud)
因此,这种事情的基本实现将是:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
基本用法是:
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
Run Code Online (Sandbox Code Playgroud)