最近在开发android 的jni程序的过程中,遇到一个问题,在jni里回调java层的函数,函数中有一个long类型的参数,后面跟一个int型的参数。在某些条件下,参数传递会出现错误。看个例子:
(1)这里有个条件,是在32位的 jni 程序中,容易造成这个错误,例如我们使用CallIntMethod()回调函数OnFunc,给签名为jlong的参数a赋值时,native c++赋值应该为long long(int64_t)类型, 如果赋值为long(这在c++中是合法的),则该参数值在java层收到时,会有错,而且后面的整形参数也会有错,非常奇怪。例如
example.java
void OnFunc(long a, int b)
{
Log.i(“OnFunc() - a:0x%x, b:0x%x\r\n”);
}
native.cpp 伪代码
CallJava()
{
JNIEnv* pEnv = GetJniEnv();
long a = 0x11223344;
long b=8;
pEnv->CallVoidMethod(java Object, jmethodID *, a, b);
}
我输出的结果是:OnFunc() - a:0x811223344,b:0x11223344.
a错也就算了,关键是b的结果错得离谱,并非我们想要的8。出现该错误的原因在于long类型的匹配上。
首先我们来看看在几种环境下的long类型的长度:
Java 中参数long 为int64_t
JNI中的jlong为int64_t
JNI中long的签名“J”,代表的是jlong,也是int64_t
而32位的native c++中long 为int32_t
64位的native c++中long为int64_t
结论:32位的JNI native库中,回调java层的函数,如果有参数签名是jlong类型,则native 给的实参必须是int64_t 类型,不能是long类型,否则java层 收到的实参不对,并导致后面的参数异常。推测这可能是java内部的jni参数打包的bug。