raku - 使用 NativeCall 将 CStruct 中的内联 CArray 传递给共享库

标签 raku nativecall

这是“How to declare native array of fixed size in Perl 6?”的后续问题。

在那个问题中讨论了如何将固定大小的数组合并到 CStruct 中。 .在 this answer建议使用 HAS 内联 CArrayCStruct .当我测试这个想法时,我在问题下方的评论部分遇到了一些无法解决的奇怪行为,因此我决定将其写为一个新问题。这是我的 C 测试库代码:

slib.c :

#include <stdio.h>

struct myStruct
{
    int A; 
    int B[3];
    int C;
};

void use_struct (struct myStruct *s) {
    printf("sizeof(struct myStruct): %ld\n", sizeof( struct myStruct ));
    printf("sizeof(struct myStruct *): %ld\n", sizeof( struct myStruct *));
    printf("A = %d\n", s->A);
    printf("B[0] = %d\n", s->B[0]);
    printf("B[1] = %d\n", s->B[1]);
    printf("B[2] = %d\n", s->B[2]);
    printf("C = %d\n", s->C);
}

要从中生成共享库,我使用了:
gcc -c -fpic slib.c
gcc -shared -o libslib.so slib.o

然后,Perl 6 代码:

第6页 :
use v6;
use NativeCall;

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

sub use_struct(myStruct $s) is native("./libslib.so") { * };

my $s = myStruct.new();
$s.A = 1;
$s.B[0] = 2;
$s.B[1] = 3;
$s.B[2] = 4;
$s.C = 5;
say "Expected size of Perl 6 struct: ", (nativesizeof(int32) * 5);
say "Actual size of Perl 6 struct: ", nativesizeof( $s );
say 'Number of elements of $s.B: ', $s.B.elems;
say "B[0] = ", $s.B[0];
say "B[1] = ", $s.B[1];
say "B[2] = ", $s.B[2];
say "Calling library function..";
say "--------------------------";
use_struct( $s );

脚本的输出是:
Expected size of Perl 6 struct: 20
Actual size of Perl 6 struct: 24
Number of elements of $s.B: 3
B[0] = 2
B[1] = 3
B[2] = 4
Calling library function..
--------------------------
sizeof(struct myStruct): 20
sizeof(struct myStruct *): 8
A = 1
B[0] = 0         # <-- Expected 2
B[1] = 653252032 # <-- Expected 3
B[2] = 22030     # <-- Expected 4
C = 5

问题 :
  • 为什么nativesizeof( $s )给出 24(而不是预期值 20)?
  • 为什么数组的内容是B在从 C 函数打印时结构不符合预期?

  • 备注 :

    我使用的是 Ubuntu 18.04 和 Perl 6 Rakudo 版本 2018.04.01,但也测试过版本 2018.05

    最佳答案

    你的代码是正确的。我刚刚修复了 MoarVM 中的错误,并向 rakudo 添加了测试,类似于您的代码:

    在 C 中:

    typedef struct {
        int a;
        int b[3];
        int c;
    } InlinedArrayInStruct;
    

    在 Perl 6 中:
    class InlinedArrayInStruct is repr('CStruct') {
        has int32 $.a is rw;
        HAS int32 @.b[3] is CArray;
        has int32 $.c is rw;
    }
    

    查看这些补丁:
    https://github.com/MoarVM/MoarVM/commit/ac3d3c76954fa3c1b1db14ea999bf3248c2eda1c
    https://github.com/rakudo/rakudo/commit/f8b79306cc1900b7991490eef822480f304a56d9

    如果你不是直接从 github 的最新源代码构建 rakudo(以及 NQP 和 MoarVM),你可能需要等待 2018.08 版本出现在这里:https://rakudo.org/files

    关于raku - 使用 NativeCall 将 CStruct 中的内联 CArray 传递给共享库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50777614/

    相关文章:

    input - perl6 有没有办法进行可编辑的提示输入?

    list - 如何获取由 Perl6 中的重复项组成的列表?

    raku - 仅在使用 repl 时编译错误

    visual-studio - Perl6 NativeCall 在 native 库中找不到符号

    parsing - 在 EOS(字符串结尾)处停止 Raku 语法

    raku - Perl6 拆分函数向数组添加额外元素

    raku - 如何将 CArray[ of-struct] 从 Raku 传递给 C?

    c - 使用 Posix fork 和管道的 NativeCall 代码不起作用

    ncurses - native 调用接口(interface) : how to translate "wchar_t"?

    raku - 在 NativeCall perl6 模块中声明指针 [void] 的奇怪消息