[英]Passing pointer from C to Java becomes NULL
我正在为 x86 开发 Android 应用程序,该应用程序需要与 C 进行一些集成。 我一直在使用 swig/JNI 来解决这个问题,并且大部分情况下都运行顺利。 但是,指针一直给我一些错误。
我的问题是我能够在模拟器(ARM)中成功引用变量地址,但在设备(x86)上,go 也没有。
使用此链接中的示例,我发现一旦该地址传递给 Java,C 中任何已分配变量的地址都会变为 NULL。 例如...
Swig 生成的 JNI:
SWIGEXPORT jlong JNICALL Java_exampleJNI_new_1intp(JNIEnv *jenv, jclass jcls) {
jlong jresult = 0 ;
int *result = 0 ;
(void)jenv;
(void)jcls;
result = (int *)new_intp();
LOGI("Result is %x", result);
*(int **)&jresult = result;
LOGI("JResult is %x", jresult);
return jresult;
}
包含 new_intp() 的源文件:
static int *new_intp() {
return (int *) calloc(1,sizeof(int));
}
我有打印语句检查地址的值,因为它起源于 C 并传递给 Java。 在 new_intp() 中,新变量被分配了一个好看的地址,但是一旦这个值返回到 JNI 并被转换为 jlong,它就会变成 NULL。
换句话说, *(int **)&jresult = result;
导致 jresult 为 0。
为什么会这样? x86 是否有一些特殊性不允许 JNI 使用指针? 还是因为我在物理设备而不是模拟器上测试它?
问候
实际上,这是一个指针别名问题。 SWIG 使用的是老式的 C 指针技术,当优化开启时,这些技术在较新的 GCC 中不起作用。 埋在 SWIG 文档中,它专门说明了要做什么:
重要的
如果您要使用通过 gcc(例如 -O2)打开的优化,请确保您还使用 -fno-strict-aliasing 进行编译。 从 gcc-4.0 开始,GCC 优化变得更加激进,并且会导致代码在打开严格的别名优化时失败。 有关详细信息,请参阅C/C++ 到 Java 类型映射部分。
在我看来,这可能是一个字节顺序问题。
*(int **)&jresult = result;
如果int
是 32 位,而jresult
是 64 位,那么在大端架构上,这可能会产生意想不到的结果。
&jresult
是一个指向 64 位值的指针,因此如果将其转换为指向 32 位值的指针,那么您将指向两个组成的 32 位字的低地址。 在大端系统中,这将是最重要的词。 因此,在将 32 位字写入 64 位值的最高有效端之后,您会得到一个 64 位值,它比您预期的值大 2^32 倍。
如果您的LOGI
调用将参数视为 32 位 int,并从 64 位值隐式向下转换,则它将给出 0。
你能看看这是否有效吗?
jresult = (jlong) result;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.