Casting a C++ long type to a JNI jlong

19,043

Solution 1

When you pass a jlong (which is 64 bit) as a pointer (which is, most likely, 32-bit) you necessarily lose data. I'm not sure what's the convention, but try either this:

CallStaticVoidMethodA(myClass, "(J)V", (jvalue*)&val); //Note address-of!

or this:

CallStaticVoidMethod(myClass, "(J)V", val); 

It's ...A methods that take a jvalue array, the no-postfix methods take C equivalents to scalar Java types.

The first snippet is somewhat unsafe; a better, if more verbose, alternative would be:

jvalue jv;
jv.j = val;
CallStaticVoidMethodA(myClass, "(J)V", &jv);

On some exotic CPU archtectures, the alignment requirements for jlong variables and jvalue unions might be different. When you declare a union explicitly, the compiler takes care of that.

Also note that C++ long datatype is often 32-bit. jlong is 64 bits, on 32-bit platforms the nonstandard C equivalent is long long or __int64.

Solution 2

CallStaticVoidMethod(myClass, "(J)V", (jvalue*)val);

This is undefined behaviour. You are casting an integer to be a pointer. It is not a pointer. You need, at the very least, to pass the address. This code would on most platforms instantly crash.

Share:
19,043
lost_bits1110
Author by

lost_bits1110

Updated on June 04, 2022

Comments

  • lost_bits1110
    lost_bits1110 almost 2 years

    I am using JNI to pass data between C++ and Java. I need to pass a 'long' type, and am doing so using something like:

     long myLongVal = 100;
     jlong val = (jlong)myLongVal;
     CallStaticVoidMethod(myClass, "(J)V", (jvalue*)val);
    

    However in Java, when the 'long' parameter is retrieved, it gets retrieved as some very large negative number. What am I doing wrong?

  • Drew Hall
    Drew Hall over 12 years
    "C++ long is 32-bit too"--true on some architectures, not on others. x64 linux usually uses 64-bit long. long long isn't available everywhere either (it's an extension IIRC).
  • Seva Alekseyev
    Seva Alekseyev over 12 years
    True, that. I'll add a qualification.
  • lost_bits1110
    lost_bits1110 over 12 years
    Thanks for your answer - unfortunately I've tried both suggseted approaches and the parameter still appears garbled when retrieved in Java, I also tried with int and float types in addition to long :( Strangely the following does work, and only for int types (though it doesn't make sense) int someInt = 100; CallStaticVoidMethod(myClass, "(I)V", (jvalue*)(jint)someInt );
  • lost_bits1110
    lost_bits1110 over 12 years
    you're absolutely right - I should be taking the address, however this still does not work for me (regardless of float, int or long type, as I tried all of these). Strangely, the following works, and only for int types (though it doesn't make any sense) int someInt = 100; CallStaticVoidMethod(myClass, "(I)V", (jvalue*)(jint)someInt );
  • lost_bits1110
    lost_bits1110 over 12 years
    DOH! It turns out I was not using CallStaticVoidMethodA, but CallStaticVoidMethod. Appending the 'A' solves the problem. Thank-you!