On 10.11.2012 10.11, "Kustaa Nyholm" <
Kustaa...@planmeca.com> wrote:
>On 4.11.2012 12.48, "Timothy Wall" <
twal...@java.net> wrote:
>
>>>
>>>but this probably forces JNA to handle endian issue of
>>>'short[] fds' so this is potentially slower than just
>>>using a byte array?
>>
>>I may be overlooking something, but I don't think endianness will be an
>>issue.
>>
>>
While waiting for THE definite explanation I experiment
a bit (haha) on my Intel (little endian) Mac:
package purejavacomm.testsuite;
import com.sun.jna.Native;
import com.sun.jna.NativeLong;
import com.sun.jna.Pointer;
public class ExperimentWithJNAEndianness {
public static class CLib {
native public Pointer malloc();
native public long memcpy(byte[] dst, byte[] src, long n);
native public long memcpy(short[] dst, byte[] src, long n);
native public long memcpy(int[] dst, byte[] src, long n);
native public long memcpy(long[] dst, byte[] src, long n);
static {
Native.register("c");
}
}
static CLib C = new CLib();
public static void main(String[] args) {
byte[] src = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
byte[] bdst = new byte[8];
short[] sdst = new short[4];
int[] idst = new int[2];
long[] ldst = new long[1];
C.memcpy(bdst, src, 8);
C.memcpy(sdst, src, 8);
C.memcpy(idst, src, 8);
C.memcpy(ldst, src, 8);
for (int i = 0; i < 8; i++)
System.out.printf("0x%02X ", 0xFF & bdst[i]);
System.out.println();
for (int i = 0; i < 4; i++)
System.out.printf("0x%04X ", 0xFFFF & sdst[i]);
System.out.println();
for (int i = 0; i < 2; i++)
System.out.printf("0x%08X ", 0xFFFFFF & idst[i]);
System.out.println();
for (int i = 0; i < 1; i++)
System.out.printf("0x%016X ", 0xFFFFFFFF & ldst[i]);
System.out.println();
System.out.println("sizeof(long) "+NativeLong.SIZE);
}
}
this outputs:
0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07
0x0100 0x0302 0x0504 0x0706
0x00020100 0x00060504
0x0706050403020100
sizeof(long) 8
So, what's my conclusion?
Obviously finding out the size of long is trivial if
one bothers to look at JNA javadoc.
The C memcpy never understand anything but bytes
so it is just copying bytes verbatim without
regards to endianness. Now I've filled the
source array with bytes in the order so that
the lower values should be lower in memory.
Now a big endian CPU should fetch the data
as follows from the start of those 8 bytes:
16 bits => 0x0001
32 bits => 0x00010203
64 bites => 0x0001020304050607
as Java is bigendian this is what the
should have happened without JNA magic,
since this is NOT what happened my conclusion
is that JNA did the endian conversion here,
as is obvious in retrospect, otherwise
the Java to C mapping as performed by JNA
would not work if users would have to worry
about the endian issue.
So back to my original C struct:
struct pollfd {
int fd; /* file descriptor */
short events; /* requested events */
short revents; /* returned events */
};
If this is passed as four shorts I only need
to worry about the swapping of hi/lo 16 bits
of 'fd' field, right?
If I pass this as two ints I will have to
worry about the two short fields 'events'
and 'revents', right?
If I pass this as long that is most effiecient
right?
If I pass this as long I need to worry about
aligning the fields within the long according
to the endianness, right?
A few questions are raised by this experiment.
Obviously this sort of experiment can be used
to find out the endianness of the C interface,
is that the preferred way or JNA has a public
method for this?
I changed the length to memcpy from int to long and
both work, how come?
In C the type of length is 'size_t'
which I presume is 64 bit. Ok it actually depends
on the JVM mode, 32 bit or 64 bit but experimenting
with -d32 and -d64 shows that the Native.SIZE
changes but using long as the return value
and length to memcpy always works, now I
don't understand what is going on?
I would have expected a crash somewhere down the line...
I experimented with leaving out the return value
of memcpu from the signature and with int and
long as well, always works. Is it safe to ignore
the return value?
br Kusti