Passing an inlined CArray in a CStruct to a shared library using NativeCall

删除回忆录丶 提交于 2019-12-10 14:53:17

问题


This is a follow-up question to "How to declare native array of fixed size in Perl 6?".

In that question it was discussed how to incorporate an array of a fixed size into a CStruct. In this answer it was suggested to use HAS to inline a CArray in the CStruct. When I tested this idea, I ran into some strange behavior that could not be resolved in the comments section below the question, so I decided to write it up as a new question. Here is is my C test library code:

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);
}

To generate a shared library from this i used:

gcc -c -fpic slib.c
gcc -shared -o libslib.so slib.o

Then, the Perl 6 code:

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 );

The output from the script is:

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

Questions:

  • Why does nativesizeof( $s ) give 24 (and not the expected value of 20)?

  • Why is the content of the array B in the structure not as expected when printed from the C function?

Note:

I am using Ubuntu 18.04 and Perl 6 Rakudo version 2018.04.01, but have also tested with version 2018.05


回答1:


Your code is correct. I just fixed that bug in MoarVM, and added tests to rakudo, similar to your code:

In C:

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

In Perl 6:

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

See these patches: https://github.com/MoarVM/MoarVM/commit/ac3d3c76954fa3c1b1db14ea999bf3248c2eda1c https://github.com/rakudo/rakudo/commit/f8b79306cc1900b7991490eef822480f304a56d9

If you are not building rakudo (and also NQP and MoarVM) directly from latest source from github, you probably have to wait for the 2018.08 release that will appear here: https://rakudo.org/files



来源:https://stackoverflow.com/questions/50777614/passing-an-inlined-carray-in-a-cstruct-to-a-shared-library-using-nativecall

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!