Passing Pointers Between C and Java Through Jni

Passing pointers between C and Java through JNI

I used the following approach:

in your JNI code, create a struct that would hold references to objects you need. When you first create this struct, return its pointer to java as a long. Then, from java you just call any method with this long as a parameter, and in C cast it to a pointer to your struct.

The structure will be in the heap, so it will not be cleared between different JNI calls.

EDIT: I don't think you can use long ptr = (long)&address; since address is a static variable. Use it the way Gunslinger47 suggested, i.e. create new instance of class or a struct (using new or malloc) and pass its pointer.

Passing pointers between C and Java through JNI

There are various handy integer types in C. The one you want is probably intptr_t or uintptr_t:

return (jlong)(intptr_t) ptr;

The difference?

  • Casting from intptr_t to jlong and back is guaranteed to work provided jlong is big enough (which you're implicitly assuming it is anyway).
  • Casting from uinttptr_t to jlong and back avoids a sign-extension, but is undefined behaviour if the uintptr_t is too big to fit in a jlong (but all "sane" architectures/compilers just use two's complement arithmetic)

Passing a pointer from JNI to Java using a long

In your example

struct myStruct_s mystruct;

is a local variable on the stack, and therefore not available after the function returns. Possubly that's just a cut-down of your code, but if not then use a malloc(sizeof(struct myStruct_s)) to get yourself a heap allocation.

That then raises the question of when you are going to free that allocation, watch out for memory leaks.

Why does the JNI C API use a pointer-to-pointer instead of straight pointers for JNIEnv?

JNIEnv is not really a pointer to a pointer, but to a data structure containing other (private) thread-specific information. The JNINativeInterface* is just the first field in the struct, and the rest aren't public. This allows for more flexibility in VM's implementation of JNI function tables.

Some links here for the benefit of those who might come across this:

  1. Threads and JNI - here it explains:

    The JNI interface pointer (JNIEnv *) is only valid in the current thread. You must not pass the interface pointer from one thread to another, or cache an interface pointer and use it in multiple threads. The Java Virtual Machine will pass you the same interface pointer in consecutive invocations of a native method from the same thread, but different threads pass different interface pointers to native methods.

  2. JNI spec

How to pass a C++ function pointer into a library's JNI functions

You need another layer of indirection. Since there's no such things as a function pointer in Java, you can't pass one to JNI. Instead, you have to pass it a Java object. Make an interface

public interface Callback {
void onAudioRecorded(int data[]);
}

Pass an instance of that to JNI. Then in JNI, write a function that calls the onAudioRecorded method of that Java object, and pass it to the function that needs a callback. remember that you need to hold an instance of that object at the JNI layer, and free it when you're finally done with it.



Related Topics



Leave a reply



Submit