我有一些C函数,我通过JNI调用它接受一个结构的指针,以及一些其他函数将分配/释放指向同一类型结构的指针,这样它就更容易处理用我的包装。令人惊讶的是,JNI文档对如何处理C结构几乎没有说明。
我的C头文件如下所示:
typedef struct _MyStruct {
float member;
} MyStruct;
MyStruct* createNewMyStruct();
void processData(int *data, int numObjects, MyStruct *arguments);
相应的JNI C包装文件包含:
JNIEXPORT jobject JNICALL
Java_com_myorg_MyJavaClass_createNewMyStruct(JNIEnv *env, jobject this) {
return createNewMyStruct();
}
JNIEXPORT void JNICALL
Java_com_myorg_MyJavaClass_processData(JNIEnv *env, jobject this, jintArray data,
jint numObjects, jobject arguments) {
int *actualData = (*env)->GetIntArrayElements(env, data, NULL);
processData(actualData, numObjects, arguments);
(*env)->ReleaseIntArrayElements(env, data, actualData, NULL);
}
...最后,相应的Java类:
public class MyJavaClass {
static { System.loadLibrary("MyJniLibrary"); }
private native MyStruct createNewMyStruct();
private native void processData(int[] data, int numObjects, MyStruct arguments);
private class MyStruct {
float member;
}
public void test() {
MyStruct foo = createNewMyStruct();
foo.member = 3.14159f;
int[] testData = new int[10];
processData(testData, 10, foo);
}
}
不幸的是,这个代码在点击createNewMyStruct()
后立即崩溃了JVM。我对JNI有点新意,不知道问题可能是什么。
编辑:我应该注意到C代码非常香草C,经过充分测试并从一个正在运行的iPhone项目移植过来。此外,该项目使用的是Android NDK框架,它允许您从JNI内部的Android项目中运行本机C代码。但是,我认为这不是严格意义上的NDK问题......这似乎是我的JNI设置/初始化错误。
答案 0 :(得分:40)
您需要使用与C struct相同的成员创建一个Java类,并通过方法env-> GetIntField,env-> SetIntField,env-> GetFloatField,env->在C代码中“映射”它们; SetFloatField等等 - 简而言之,大量的手工劳动,希望已经存在自动执行的程序:JNAerator(http://code.google.com/p/jnaerator)和SWIG(http://www.swig.org/)。两者都有其优点和缺点,选择取决于你。
答案 1 :(得分:10)
崩溃是因为Java_com_myorg_MyJavaClass_createNewMyStruct
被声明为返回jobject
,但实际上正在返回struct MyStruct
。如果您在启用CheckJNI的情况下运行此操作,则VM会大声抱怨并中止。您的processData()
函数对于arguments
传递的内容也会感到非常不满。
jobject
是托管堆上的对象。它可以在声明的字段之前或之后有额外的东西,并且字段不必以任何特定的顺序在内存中布局。因此,您无法在Java类之上映射C结构。
在前面的答案中确定了处理此问题的最简单方法:使用JNI函数操纵jobject
。通过适当的调用从Java或对NewObject
,Get
/ Set
对象字段分配对象。
这里有各种“欺骗”的方法。例如,您可以在Java对象中包含byte[]
,其中包含sizeof(struct MyStruct)
个字节,然后使用GetByteArrayElements
获取指向它的指针。有点难看,特别是如果你想从Java端访问字段。
答案 2 :(得分:6)
C结构是变量的集合(有些是函数指针)。传递给java并不是一个好主意。一般来说,问题是如何将更复杂的类型传递给java,比如指针。
在JNI书中,建议将指针/结构保留在本机和导出操作中。你可以阅读一些有用的文章。 The JavaTM Native Interface Programmer's Guide and Specification,我读过。 9.5 Peer Classes有解决方案来处理它。
答案 3 :(得分:0)
这不是一个理想的解决方案,但它可以为您节省一点时间,它至少会为您提供一个可以编辑的骨架。此功能可以添加到IDE中,但没有大的需求,它可能不会发生。大多数IDE甚至不支持混合语言项目,更不用说让它们相互交谈了。