【问题标题】:How to declare native array of fixed size in Perl 6?如何在 Perl 6 中声明固定大小的原生数组?
【发布时间】:2018-06-06 14:39:44
【问题描述】:

我正在尝试在 Perl 6 中声明以下 C 结构:

struct myStruct
{
    int A[2]; //<---NEED to declare this
    int B;
    int C;
};

我的问题是我不知道如何使用内置的 NativeCall api 声明 int A[2]; 部分。

所以我所拥有的是:

class myStruct is repr('CStruct') {
    has CArray[int32] $.A;
    has int32 $.B;
    has int32 $.C;
};

但是,我知道 has CArray[int32] $.A; 部分是错误的,因为它没有在我的结构中声明仅占用 2 个 int32 大小的部分。

【问题讨论】:

标签: raku nativecall


【解决方案1】:

更新 2:事实证明,这在我第一次发布此答案时不起作用,因此是 cmets。我仍然没有测试它,但它肯定可以按照 Tobias 对Passing an inlined CArray in a CStruct to a shared library using NativeCall 的回答工作。 \o/


我尚未对此进行测试,但在使用 Rakudo 编译器版本 2018.05 时应该可以使用:

use NativeCall;
class myStruct is repr('CStruct') {
    HAS int32 @.A[2] is CArray;
    has int32 $.B;
    has int32 $.C;
}
  • HAS 而不是has 导致属性是内联的而不是指针;

  • int32 而不是 int 是因为 Perl 6 的 int 类型与 C 的 int 类型不同,而是特定于平台(通常是 64 位);

  • @ 而不是$ 将属性标记为Positional(“支持按索引查找值”)而不是标量(被视为单个事物);

  • [2] 将位置数据“塑造”为具有 2 个元素;

  • is CArrayCArray 绑定为位置数据的容器逻辑;

  • This commit from April this year 连接 is repr('CStruct') 以使用声明的属性信息来适当地分配内存。

我从a search of the #perl6 logs for CArray 发现了这个功能,并从a search of Rakudo commits for the commit message title 发现它已经登陆master 和2018.05。

【讨论】:

  • 不错的解决方案!我现在对此进行了测试,它似乎有效。我遇到的唯一问题是如何在将数组传递给 C 库之前对其进行初始化。我尝试了my $s = myStruct.new(); $s.A[0] = 1,但当从我的 C 测试库中打印时,它只输出A 的垃圾。也许我做错了什么。我可以在 Perl 6 中设置字段 BC 很好,并且它们可以从 C 中正确打印。C 中的 sizeof( struct myStruct) 是 16 个字节,而在 Perl 6 中 nativesizeof(...) 也给出16 字节..
  • @HåkonHægland 尝试使用.ASSIGN-POS 而不是[...]
  • @raiph 我试过$s.A.ASSIGN-POS(0, 1),但它仍然对我不起作用。我想知道这里发生了什么?我已经尝试过 Rakudo 版本 2018.04.01 和 2018.05 但没有区别。它对你有用吗?
  • 不,我根本没有测试过。我真的不知道 C 或 nativecall 的东西,我只是四处寻找似乎是结构布局/分配的解决方案,而不是读/写,当我看到一个关于使用 .ASSIGN-POS 的提示时的[...]。我必须跑去上班,正如我所说,我不知道 C 等,但如果我有时间,我想我会在你在 OP 的问题上链接的问题中专注于 timotimo 的 cmets,如果我有这样做之后没有任何乐趣,我会弹出 #perl6-dev 并询问。祝你和 OP 好运。
【解决方案2】:

Declaring an array inside a Perl 6 NativeCall CStruct

还有其他方法,但最简单的方法是代替数组,只需声明每个单独的项目。

class myStruct is repr('CStruct') {
    has int32 $.A0;
    has int32 $.A1;
    ... as many items as you need for your array ...
    has int32 $.B;
    has int32 $.C;
};

【讨论】:

  • 到目前为止,这似乎是唯一“可行”的解决方案,但很不方便。必须复制、粘贴和重命名成员需要时间,并且与访问 [ ] 索引语法支持的数组相比,访问数据非常不切实际。
【解决方案3】:

所以我对此做了一些实验并查看了文档,看起来 CArray 类型处理整形的方式与 Perl6 数组不同。

你得到的最接近的东西是分配构造函数,它在数组中预分配空间,但它不强制大小,所以你可以添加更多东西。

您的类定义很好,但您想在BUILD 子方法中分配数组。

https://docs.raku.org/language/nativecall#Arrays

(进一步思考)

你可以有两个对象。一个用于内部,一个用于结构。

结构有一个CArray[int32] 数组。内部数据对象有一个整形 int32 强制转换数组my int3 @a[2]。那么你只需要在两者之间进行复制即可。

getter 和 setter 存在于 main 对象上,而您只是在想与 lib 对话时才使用 struct 对象?

【讨论】:

  • " 看起来 CArray 类型处理整形的方式与 Perl6 数组不同" - 我想知道他们是否故意省略了此功能以防止缓冲区溢出问题。至少对于 Perl 中的非固定数组,它可以增长.. 但是固定的数组可能会破坏 Perl 6 的安全目标。
【解决方案4】:

这并没有真正声明一个固定大小的数组,而是对其值的大小进行了限制:您可以尝试使用where 来限制数组的大小。 CArray 不是一个位置(因此不能用@ sigil 声明),但它确实有elems method

use NativeCall; 
my CArray[int32] $A where .elems < 2

也就是说,至少在语法上是正确的。这是否会在其他地方破坏该程序还有待观察。你能试试吗?

【讨论】:

  • 这是问题所在:say @A.WHAT; (Array[CArray[int32]]) 通过使用@,您会得到一个 CArray 数组。而且你不能塑造一个标量。您也不能将 CArray 绑定到成形数组。你可以调用CArray.new(:shape(2)),但构造函数不处理它。
  • @Scimon 没错。我会看看如何改变它。
  • @Scimon 更改为其他可能的方式。
  • where 是一个运行时构造(保护可以分配/绑定到$A 的内容),在编译时指导内存布局总是为时已晚,这是OP 的问题。
  • @raiph 我在编译时看不到其他方法,除了将数组的元素放在一起,这对于大数组可能不切实际。这在原始语法中根本没有预见到。
猜你喜欢
  • 2018-03-31
  • 1970-01-01
  • 2014-04-26
  • 2012-08-09
  • 1970-01-01
  • 2010-12-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多