问题
I'm am trying to declare the following C struct in Perl 6:
struct myStruct
{
int A[2]; //<---NEED to declare this
int B;
int C;
};
My problem is that I don't know how to declare the int A[2];
part using the built in NativeCall api.
So for what I have is:
class myStruct is repr('CStruct') {
has CArray[int32] $.A;
has int32 $.B;
has int32 $.C;
};
However, I know that the has CArray[int32] $.A;
part is wrong as it does not declare a part in my struct that takes up ONLY 2 int32
sizes.
回答1:
Update 2: It turned out that this didn't work at the time I first posted this answer, hence the comments. I still haven't tested it but it must surely work per Tobias's answer to Passing an inlined CArray in a CStruct to a shared library using NativeCall. \o/
I haven't tested this, but this should work when using Rakudo compiler release 2018.05:
use NativeCall;
class myStruct is repr('CStruct') {
HAS int32 @.A[2] is CArray;
has int32 $.B;
has int32 $.C;
}
HAS
instead ofhas
causes the attribute to be inline rather than a pointer;int32
instead ofint
is because the Perl 6int
type isn't the same as C'sint
type but is instead platform specific (and usually 64 bit);@
instead of$
marks the attribute as being Positional ("supports looking up values by index") instead of scalar (which gets treated as a single thing);[2]
"shapes" the Positional data to have 2 elements;is CArray
binds aCArray
as the Positional data's container logic;This commit from April this year wired up the
is repr('CStruct')
to use the declared attribute information to appropriately allocate memory.
Fwiw I found out about this feature from a search of the #perl6 logs for CArray and found out it had landed in master and 2018.05 from a search of Rakudo commits for the commit message title.
回答2:
See Declaring an array inside a Perl 6 NativeCall CStruct
There are other ways, but the easiest is instead of an array, just declare each individual item.
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:
So I've done some experimentation on this and taken a look at the docs and it looks like the CArray type doesn't handle shaping the same way as Perl6 Arrays.
The closest thing you've got it the allocate constructor that preallocates space in the array but it doesn't enforce the size so you can add more things.
Your class definition is fine but you'd want to allocate the array in the BUILD
submethod.
https://docs.raku.org/language/nativecall#Arrays
(Further thought)
You could have two objects. One internal and one for the struct.
The Struct has a CArray[int32]
array. The internal data object has a shaped int32 cast array my int3 @a[2]
. Then you just need to copy between the two.
The getters and setter live on the main object and you use the struct object just when you want to talk to the lib?
回答4:
This does not really declare an array of fixed size, but puts a constraint on the size of its value: You can try and use where to constraint the size of the array. CArray
is not a positional (and thus cannot be declared with the @
sigil) but it does have the elems method.
use NativeCall;
my CArray[int32] $A where .elems < 2
That is, at least, syntactically correct. Whether that breaks the program in some other place remains to be seen. Can you try that?
来源:https://stackoverflow.com/questions/50723156/how-to-declare-native-array-of-fixed-size-in-perl-6