如何将C结构来回传递给JNI中的Java代码?

我有一些C函数,我通过JNI调用一个指向结构的指针,还有一些函数会分配/释放一个指向相同types结构的指针,以便处理我的包装器。 令人惊讶的是,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,是经过充分testing,并从一个正在运行的iPhone项目移植。 另外,这个项目正在使用Android NDK框架,它允许您从JNI内的Android项目运行本机C代码。 但是,我不认为这是严格的NDK问题…这似乎是我的一个JNI设置/初始化错误。

您需要使用与C struct相同的成员创build一个Java类,并通过env-> GetIntField,env-> SetIntField,env-> GetFloatField,env-> SetFloatField等方法在C代码中“映射”总之,大量的手工劳动,希望已经存在自动执行的程序:JNAerator( http://code.google.com/p/jnaerator )和SWIG( http://www.swig.org/ )。 两者各有利弊,select取决于你。

这是因为Java_com_myorg_MyJavaClass_createNewMyStruct被声明为返回“jobject”,但实际上是返回struct MyStruct。 如果您在启用CheckJNI的情况下执行此操作,VM将会大声抱怨并中止。 你的processData()函数也会对于它在“参数”中交给的东西感到相当不高兴。

jobject是托pipe堆上的一个对象。 它可以在声明的字段之前或之后有额外的东西,而且这些字段不必以任何特定的顺序排列在内存中。 所以你不能在Java类之上映射C结构。

在以前的答案中确定了处理这个问题的最简单的方法:使用JNI函数处理工作对象。 从Java或NewObject分配对象,通过适当的调用获取/设置对象字段。

这里有很多种“欺骗”的方法。 例如,您可以在包含sizeof(struct MyStruct)字节的Java对象中包含一个byte [],然后使用GetByteArrayElements获取指向它的指针。 有点难看,特别是如果你想访问Java端的字段。

C结构是variables的集合(有些是函数指针)。 传递给java不是一个好主意。 一般来说,如何将更复杂的types传递给j​​ava就像指针一样是个问题。

在JNI书中,build议将指针/结构保持原生,并将其导出为java。 你可以阅读一些有用的文章。 JavaTM本地接口程序员指南和规范,我读过。 9.5对等类有一个解决scheme来处理它。

  1. 在Java和C ++端创build类,只需放入成员variables即可。 C ++结构体实际上只是具有公共数据成员的类。 如果你真的在纯粹的C,现在停止阅读。
  2. 使用您的IDE自动为成员variables创buildsetter和getter。
  3. 使用javah从Java类生成C头文件。
  4. 在C ++端做一些编辑,使setter和getter匹配生成的头文件。
  5. 放入JNI代码。

这不是一个理想的解决scheme,但它可以为您节省一点时间,它至less会给您一个可以编辑的框架。 这个function可以添加到IDE,但没有大的需求,它可能不会发生。 大多数IDE甚至不支持混合语言项目,更不用说让他们相互交stream了。