Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass parameters per reference from c++ to java via jni

I'm trying to pass a variable from c++ to java per reference via JNI. For the beginning I've tried it with some simple code:

Java

public static void inc(int val) {
  System.out.println("inc called: " + val);
  val++;
}

public static void dec(int val) {
  System.out.println("dec called: " + val);
  val--;

}

This should simply in-/decrement a variable created in c++ code with a Java method. The c++ part looks like this:

C++

jmethodID jDec = env->GetStaticMethodID(cls, "dec", "(I)V");
jmethodID jInc = env->GetStaticMethodID(cls, "inc", "(I)V");

jint val = 10;

printf("%d\n", val);
env->CallStaticVoidMethod(cls, jDec, &val);
printf("%d\n", val);
env->CallStaticVoidMethod(cls, jInc, val);
printf("%d\n", val);

As you see, I tried both, per reference and per value.

Output

10
dec called: -401031272
10
inc called: 10
10

Within the c++ code, the value is all the time 10, in Java it is either the address or the value.

Would be nice if you could give me a hint, thank you very much in advance.

like image 883
sosnet Avatar asked Feb 12 '23 10:02

sosnet


1 Answers

As Wojtek said, Java passes arguments by value. You can add a return value your Java code:

public static int inc2(int val) {
    System.out.println("inc called: " + val);
    return val + 1;
}

and then call it from C++:

jmethodID inc2 = env->GetStaticMethodID(cls, "inc2", "(I)I");
jint result = env->CallStaticIntMethod(cls, inc2, val);
printf("inc2: %d\n", result);

Another approach is to use a wrapper class instead:

public class IntWrapper {

    private int value;

    public IntWrapper(int value) {
        setInt(value);
    }

    public int getInt() {
        return value;
    }

    public void setInt(int value) {
        this.value = value;
    }
}

and the following Java method:

public static void inc3(IntWrapper val) {
    val.setInt(val.getInt()+1);
}

You can then call this from your C++ code:

// create wrapper object
jclass wrapper = env->FindClass("IntWrapper");
jmethodID constructor = env->GetMethodID(wrapper, "<init>", "(I)V");
jobject wrapperObject = env->NewObject(wrapper, constructor, val);

// print value before increment
jmethodID getInt = env->GetMethodID(wrapper, "getInt", "()I");
jint ret = env->CallIntMethod(wrapperObject, getInt);
printf("Wrapper value: %d\n", ret);

// call inc3
jmethodID inc3 = env->GetStaticMethodID(cls, "inc3", "(LIntWrapper;)V");
env->CallStaticVoidMethod(cls, inc3, wrapperObject);

// print result
ret = env->CallIntMethod(wrapperObject, getInt);
printf("Wrapper value after increment: %d\n", ret);

Alternatively you could use an int[] instead of the wrapper class as suggested by Wojtek.

like image 87
Alexander Oprisnik Avatar answered Feb 15 '23 11:02

Alexander Oprisnik