将指针从C传递到Java变为NULL

我正在开发一款适用于x86的Android应用程序,它需要与C进行一些集成。我一直在使用swig / JNI来完成这项工作,而且大部分内容都在顺利运行。 但是,指针一直给我一些错误。

我的问题是我能够在模拟器(ARM)中成功引用变量地址,但在设备(x86)上,事情并不顺利。

使用此链接中的示例,我发现一旦此地址转移到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)); } 

我有print语句检查地址的值,因为它来自C并传递给Java。 在new_intp()中,新变量被分配了一个好看的地址,但是一旦这个值返回到JNI并被转换为jlong​​,它就会变成NULL。

换句话说, *(int **)&jresult = result; 导致jresult为0。

为什么会这样? 是否有一些特殊性的x86不允许JNI使用指针? 或者是因为我在物理设备而不是模拟器上测试它?

问候

在我看来它可能是一个字节序问题。

 *(int **)&jresult = result; 

如果int是32位,而jresult是64位,那么在big-endian架构上,这可能会产生意想不到的结果。

&jresult是指向64位值的指针,因此如果将其转换为指向32位值的指针,那么您将指向两个组成32位字的低位地址。 在大端系统中,这将是最重要的词。 因此,在将32位字写入64位值的最高端后,您将获得64位值,这比您预期的大2 ^ 32倍。

如果您的LOGI调用将参数视为32位int,并从64位值隐式向下转换它,那么它将给出0。

你能看出这是否有效吗?

 jresult = (jlong) result; 

实际上,这是一个指针别名问题。 SWIG正在使用老式的C指针技术,当优化开启时,这些技术在较新的GCC中不起作用。 在SWIG文档中,它专门说明要做什么 :

重要

如果要使用gcc打开优化(例如-O2),请确保使用-fno-strict-aliasing进行编译。 从gcc-4.0开始,GCC优化变得更加激进,并且会导致代码在启用严格别名优化的情况下失败。 有关更多详细信息,请参阅C / C ++到Java类型映射部分。