7

我有一个第三方 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) 是原生的('test_lib') { ... }
我的 $struct = myStruct.new();
填充结构($结构);# 到目前为止我尝试过的任何变体都会出现 seg 错误

我怎样才能使这项工作?

4

3 回答 3

2

正如其他人所说,目前似乎没有任何方法可以实现这一目标。

我已经求助于定义一个新的 C 函数作为解决方法。该函数有效地充当访问器方法,仅返回我需要的字段作为离散的 NativeCall 友好指针。

希望社区能在某个时候为这个案例提供适当的支持。

于 2017-12-21T17:22:22.513 回答
1

在撰写本文时,这似乎没有得到处理。
作为一种解决方法,我的做法是让宏生成 32 int8,充分放置字段名称。

于 2017-10-03T19:58:09.620 回答
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);
     }
  }
  
}

让我解释:

用于定义静态尺寸元素的“HAS”声明器已经在 NativeCall 中使用了一段时间,所以这不是实验部分。棘手的部分是“方法 myString”。它允许类 A 的使用者设置和获取 @!myString 属性,就好像它是一个正确的属性,而不是一个数组。

如果 @!myString 中的数据首先从 C 中读取,则 $cache 状态变量将为空。然后通过解码的 Buf 创建 Str 对象并返回。希望对用户隐藏对象实现中看到的复杂性,以便:

my $a = c_function_that_returns_A();
$a.myString;

...将按预期工作,同样:

$a.myString = 'Crab';

...也可以毫无问题地工作。

不幸的是,像 setCharArray() 这样的辅助函数需要迭代来设置 @!myString,但希望将来会改变。

重要警告——此实现假定一旦分配对象,对 @!myString 的更改仅限于 Raku 端,否则一旦设置,$cached 值将屏蔽它们。目前,我真的没有找到解决方法,除非您想在每次需要访问 @!myString 时花费这些周期来创建一个新的 Str a-fresh。

于 2020-07-22T20:49:39.227 回答