我有一个第三方C库,它定义了一个类似于:
的结构struct myStruct {
int a;
int b;
char str1[32];
char str2[32];
};
一个函数,它接受一个指向这个结构的指针并填充它。我需要我的Perl6本机调用来提供该结构,然后读取结果。
到目前为止,我已经在Perl6中定义了结构:
class myStruct is repr('CStruct') {
has int32 $.a;
has int32 $.b;
has Str $.str1; # Option A: This won't work as Perl won't know what length to allocate
has CArray[uint8] $.str2; # Option B: This makes more sense, but again how to define length?
# Also, would this allocate the array in place, or
# reference an array that is separately allocated (and therefore not valid)?
}
和本地电话一样:
sub fillStruct(myStruct) is native('test_lib') { ... } my $struct = myStruct.new(); fillStruct($struct); # Gives a seg fault with any variation I've tried so far
我该如何做到这一点?
答案 0 :(得分:2)
正如其他人所说,目前似乎没有办法实现这一目标。
我已经尝试将新的C函数定义为变通方法。该函数有效地充当一个访问器方法,只返回我需要的字段作为离散的NativeCall友好指针。
希望社区能够在某些时候为这个案例提供适当的支持。
答案 1 :(得分:1)
在撰写本文时,似乎并未处理此事
作为一种解决方法,我的看法是让宏生成32 int8
,充分放置字段名称。
答案 2 :(得分:0)
从2020年7月开始,您应该可以执行以下操作:
sub setCharArray($a, $s, $l, $c is rw) {
die 'Too many chars!' unless $s.chars <= $l;;
$c = $s if $c;
my $chars = $a.encode;
$a[$_] = $chars[$_] for ^$chars.elems;
$a[$chars.elems] = 0 unless $s.elems == 128;
}
class A repr<CStruct> is export {
HAS uint8 @!myString[128] is CArray;
state Str $cached;
method myString is rw {
Proxy.new:
FETCH => sub($) {
return if $cached;
$cached = Buf.new(@!myString).decode
},
STORE => $, Str $s is raw {
setCharArray(@!myString, $s, 128, $cached);
}
}
}
让我解释一下:
在NativeCall中已经有一段时间定义静态大小元素的“ HAS”声明符了,所以这不是实验部分。棘手的部分是“方法myString”。它允许类A的使用者设置@!myString属性并从中获取属性,就好像它是适当的属性,而不是数组一样。
如果首先从C中读取@!myString中的数据,则$ cache状态变量将为空。然后通过解码的Buf创建Str对象并返回。希望对用户隐藏对象实现中看到的复杂性,以便:
my $a = c_function_that_returns_A();
$a.myString;
...将按预期工作,并且类似:
$a.myString = 'Crab';
...也可以正常工作。
不幸的是,像setCharArray()这样的辅助函数需要迭代设置@!myString,但希望将来会改变。
重要注意事项-此实现假定一旦分配了对象,对@!myString的更改仅限于Raku端,否则,一旦设置,$ cached值将对其进行屏蔽。目前,我还没有真正的解决方法,除非您想花费时间来每次需要访问@!myString时都创建一个新的Str a-fresh。