问题描述
我如何进行这项工作?
更新:在搜索了包括Raku规范测试的Github之后,在这里,我还没有找到任何传递CArray [of-structs]的示例。 Here there is a post by Christoph自2017年以来提供了“解决方法”。
Christoph的解决方案可能有效,但如果没有更好的解决方案,则在NativeCall中会更好。
在Github上有a Rakudo test that uses a int TakeAStructArray(Struct **structs)
,如果您可以编写一个C函数来重新包装其args以转发到TakeAnArrayOfStruct( struct Struct[])
,这可能会有所帮助。
下面,JJMerelo怀疑我由于Rakudo中的错误而失败。
我有一个 C 函数,该函数使用与使用的timespec结构类似的timespec结构 在NativeCall文档中:
struct 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(沼泽地)打来的电话不起作用:
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 )
起作用。
解决方法
前一段时间我遇到了这个确切的问题,这迫使我写了a workaround
简短答案,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) )
)
}
以及以下方法以适当的索引分配结构
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,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