I try to call a short** in C with JNA.
The C looks like this:
void compute(short** in, int row, int col) {
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
printf("in[%d][%d] = %d\n", i,j, in[i][j]);
}
}
}
Passing a short[][] from JNA doesn't work.
The JNA documentation say "To map a native multi-dimensional array, use a single-dimensional Java array" but it doesn't work. When calling
'nativeLib.compute(new short[] { 1, 2, 3, 4 }, 2, 2); I get: java.lang.Error: Invalid memory access at com.sun.jna.Native.invokeVoid(Native Method)
It seems that a PointerByReference is needed, I tried to fill the PointerByReference with PointerByReference that contains short values but it doesn't work:
Pointer pointerOfArray = new Memory(row * col * Native.getNativeSize(Short.TYPE));
for(int i=0;i<row;i++) {
Pointer pointer = new Memory(col * Native.getNativeSize(Short.TYPE));
for(int j=0;j<col;j++) {
pointer.setShort(j*Native.getNativeSize(Short.TYPE), in[i][j]);
}
pointerOfArray.setPointer(i*row*Native.getNativeSize(Short.TYPE), pointer);
}
I also tried:
Pointer pointer = new Memory(4*Short.SIZE);
Pointer pointer1 = new Memory(2*Short.SIZE);
pointer1.setShort(0,(short)1);
pointer1.setShort(Short.SIZE,(short)2);
Pointer pointer2 = new Memory(2*Short.SIZE);
pointer2.setShort(0,(short)3);
pointer2.setShort(Short.SIZE,(short)4);
pointer.setPointer(0, pointer1);
pointer.setPointer(2*Short.SIZE, pointer2);
nativeLib.compute(new PointerByReference(pointer), 2,2);
But I get in[0][0] = 3184
in[0][1] = 10460
in[1][0] = 3344
in[1][1] = 10460
Does anyone have an idea? I can't change the C signature, I have to deal with this short**
Thanks a lot.
Solution
I finnaly succed! doing this:
short[][] in = {
{1,2,3},
{4,5,6},
};
Pointer[] data = new Pointer[in.length];
for(int i=0;i<in.length;i++) {
data[i] = new Memory(2*Short.SIZE);
data[i].write(0, in[i], 0,in[0].length);
}
nativeLib.compute(data, in.length,in[0].length);
With result:
in[0][0] = 1
in[0][1] = 2
in[0][2] = 3
in[1][0] = 4
in[1][1] = 5
in[1][2] = 6
Thanks a lot!
JNA only handles single dimension arrays.
And, technically, so does C. A short *
could be a 1d, 2d, or 3d array. You wouldn't know unless you knew the internals. Only by reading documentation do you know that the function is expecting a 2D array. All you're really doing is passing a pointer to the first element of the array (total length row*col), and then use (rowIndex * col + colIndex) to fetch the result. In JNA you'd just use a 1D array to match.
In this case, however, you have a short **
so you know you have a 1D array of pointers, each pointer pointing to a 1D array of short
s. In JNA, you create an array of pointers (Pointer[]
) for the first *; each will point to the first "column" of a new row (the second *).
The Invalid Memory Access
error indicates you have not properly allocated the Native memory, and gives you a strong hint at the answer: you cannot simply pass a primitive array as a parameter. You must allocate its memory, either by using the Memory
class or by including the array as part of a Structure
.
The new short[] {1, 2, 3, 4}
doesn't work here, because you haven't allocated native-side memory to support the java memory for that array. You were on the right track with that memory allocation you did by using the Memory
class.
In C, the short** in
is expecting an array of pointers. So you should start out by declaring an array of pointers:
Pointer[] p = new Pointer[row];
Then you'll set the pointers for each row, allocating memory:
p[0] = new Memory(col * Native.getNativeSize(Short.TYPE));
p[1] = new Memory(col * Native.getNativeSize(Short.TYPE));
Now, you can write your array values. You could iterate over the columns with offset and setShort()
but you can also write directly using Pointer.write() e.g.,
p[0].write(0, new short[] {1, 2}, 0, 2);
p[1].write(0, new short[] {3, 4}, 0, 2);
Then you would pass p
to the native C for in
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With