使用 NativeCall 将 CStruct 中的内联 CArray 传递到共享库
Passing an inlined CArray in a CStruct to a shared library using NativeCall
这是“How to declare native array of fixed size in Perl 6?”的后续问题。
在那个问题中讨论了如何将固定大小的数组合并到 CStruct
中。在this answer it was suggested to use HAS
中内联一个CArray
在CStruct
中。当我测试这个想法时,我 运行 遇到了一些无法在问题下方的评论部分解决的 st运行ge 行为,因此我决定将其写为一个新问题。这是我的 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 代码:
p.p6:
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)?
为什么从C函数打印出来的结构体中数组B
的内容和预期的不一样?
注:
我正在使用 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
这是“How to declare native array of fixed size in Perl 6?”的后续问题。
在那个问题中讨论了如何将固定大小的数组合并到 CStruct
中。在this answer it was suggested to use HAS
中内联一个CArray
在CStruct
中。当我测试这个想法时,我 运行 遇到了一些无法在问题下方的评论部分解决的 st运行ge 行为,因此我决定将其写为一个新问题。这是我的 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 代码:
p.p6:
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)?为什么从C函数打印出来的结构体中数组
B
的内容和预期的不一样?
注:
我正在使用 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