0

I am doing Android development in Java, with some native parts (external libraries) written in C++.

I'd like to pass a byte[] from the managed (Java) application to the native (C++) library:

// Declaration for the native method in Java
private native void someMethod(byte[] data);

On the native side, i'd like to use the byte array as arguments to another provided native function.

I've read about a JNI method for converting (copying) the array data into a compatible type (GetByteArrayElements), however that leaves me with a jbyte * type, which is incompatible with the library i am using (The library defines it's own nByte type, which is an unsigned char).

What would be the best option for this scenario?

Should i stick to the method i've described using JNI, and convert the jbyte array type into the appropriate nByte array? any other option?

lysergic-acid
  • 19,570
  • 21
  • 109
  • 218
  • 1
    `reinterpret_cast(...)`? – johnchen902 Jul 14 '13 at 11:07
  • The element width (8 bits vs portable char) is the less important of the issues; It's unlikely to change across Android NDK versions. More important is the integer range of the elements (signed vs unsigned). Is `byte[] data` specifically created as a blob that satisfies both issues? – Tom Blodget Jul 14 '13 at 14:20
  • I am not 100% sure i understood your question: you're asking what sort of data does my array contain? why is that the biggest issue here? – lysergic-acid Jul 14 '13 at 14:31
  • A Java `byte` has a range of -128 to 127. An `nByte` in your library on Android NDK presumably has a range of 0 to 255. If you need that full range in your data, you'd have to use -128 to -1 on the Java side to represent 128 to 255 in an `nByte`. Only then would a pointer cast make sense. If you happen to just be passing the data from one library function to another as an opaque blob then no problem. Otherwise, you really have to know what `nByte` represents. – Tom Blodget Jul 14 '13 at 15:55
  • My code is responsible for the serialization to byte[] so I have the control to do this right. I don't see the point of passing a blob opaque structure though.. what can be the need for such a thing... ? – lysergic-acid Jul 14 '13 at 16:38
  • I'm just referring to `byte[] data` as a blob since it apparently is not meant to be interpreted as a 1-D array of 8-bit two's complement signed integers. Since you are creating it appropriately on the Java side—just as the library function needs it—to the JNI code, it is a blob and the pointer can be cast and passed to the library function. – Tom Blodget Jul 14 '13 at 17:27

1 Answers1

1

Should I stick to the method I've described using JNI, and convert the jbyte array type into the appropriate nByte array?

Yes, since jbyte and nByte are different types, this appears to be the only reliable way without triggering undefined behavior. In practice, it is very likely that the size of nByte is the same as that of jbyte, so you could get by with re-interpreting the pointer of jbyte* as nByte*, but this is not a portable solution.

The story would have been different if your library took int8_t of <cstdint>, then you would be able to reinterpret the pointer of jbyte as a pointer of int8_t without negative consequences.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • `jbyte` is `signed char`, and OP has stated `nByte` is `unsigned char`. Why isn't it portable? – johnchen902 Jul 14 '13 at 11:14
  • @johnchen902 C++ standard guarantees raw memory access only to `char` and `unsigned char`, but not to `signed char`. Conversion through pointer could break on 1-s complement and signed magnitude computers, making it non-portable. [Here is some relevant discussion](http://stackoverflow.com/a/8386615/335858) (also in the comments). – Sergey Kalinichenko Jul 14 '13 at 11:22
  • Ok (And I later find out that `jbyte` is actually `signed 8 bits` instead of `signed char`) – johnchen902 Jul 14 '13 at 11:30
  • @dasblinkenlight thanks. I'm trying to get myself familiar with native concepts (not too familiar with all those casting options). reinterpret_cast seems to work, but i wonder if that may break on other platforms, for example in case nByte will be defined differently (or even jbyte). – lysergic-acid Jul 14 '13 at 12:02
  • @lysergic-acid reinterpret cast (which is very much equivalent to C-style cast) may fail even on platforms where `nByte` and `jbyte` are defined in the same way, but the underlying hardware uses different representation for negative values. In practice, it is very unlikely, because 2-s complement representation is prevalent, but it's better to be safe than sorry. – Sergey Kalinichenko Jul 14 '13 at 12:08
  • Also, is the other side of conversion safe? it seems to crash at runtime... jbyte* d = reinterpret_cast(eventData); // eventData is of nByte& type – lysergic-acid Jul 14 '13 at 12:57
  • 1
    @lysergic-acid You cannot reinterpret a reference as a pointer, but `reinterpret_cast(&eventData)` could work. – Sergey Kalinichenko Jul 14 '13 at 13:09