如何在JNI中来回传递C结构到Java代码?

Nik*_*man 64 c java java-native-interface android-ndk

我有一些C函数,我通过JNI调用它接受一个结构的指针,以及一些其他函数,它们将分配/释放一个指向同一类型结构的指针,这样它就更容易处理我的包装器.令人惊讶的是,JNI文档对如何处理C结构几乎没有说明.

我的C头文件看起来像这样:

typedef struct _MyStruct {
  float member;
} MyStruct;

MyStruct* createNewMyStruct();
void processData(int *data, int numObjects, MyStruct *arguments);
Run Code Online (Sandbox Code Playgroud)

相应的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);
}
Run Code Online (Sandbox Code Playgroud)

...最后,相应的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);
  }
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,这个代码在命中后立即崩溃了JVM createNewMyStruct().我对JNI有点新意,不知道问题是什么.

编辑:我应该注意到C代码非常香草C,经过充分测试并从一个正在运行的iPhone项目移植.此外,该项目使用的是Android NDK框架,它允许您从JNI内部的Android项目中运行本机C代码.但是,我认为这不是严格意义上的NDK问题......我认为这似乎是一个JNI设置/初始化错误.

iir*_*ekm 41

您需要使用与C struct相同的成员创建一个Java类,并通过方法env-> GetIntField,env-> SetIntField,env-> GetFloatField,env-> SetFloatField等在C代码中"映射"它们 - 简而言之,大量的手工劳动,希望已经存在自动执行的程序:JNAerator(http://code.google.com/p/jnaerator)和SWIG(http://www.swig.org/).两者都有其优点和缺点,选择取决于你.

  • 你能粘贴一些这种集成的简单代码示例吗? (14认同)
  • @Centurion我知道URL通常不受欢迎,但这是一个评论,我发现这个网页非常有助于搞清楚这些东西:http://www3.ntu.edu.sg/home/ehchua/programming/java/JavaNativeInterface html的#ZZ-5.1 (4认同)

fad*_*den 10

它崩溃了,因为Java_com_myorg_MyJavaClass_createNewMyStruct声明返回jobject,但实际上是返回struct MyStruct.如果您在启用CheckJNI的情况下运行此操作,则VM会大声抱怨并中止.你的processData()功能也会对它的内容感到非常不满arguments.

A jobject是托管堆上的对象.它可以在声明的字段之前或之后有额外的东西,并且字段不必以任何特定的顺序在内存中布局.因此,您无法在Java类之上映射C结构.

在前面的答案中确定了处理此问题的最直接的方法:jobject使用JNI函数进行操作.分配从Java或对象NewObject,Get/ Set用适当的调用该对象的字段.

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


qrt*_*tt1 7

C结构是变量的集合(有些是函数指针).传递给java并不是一个好主意.一般来说,问题是如何将更复杂的类型传递给j​​ava,比如指针.

在JNI书中,建议将指针/结构保留为原生和导出操作到java.你可以阅读一些有用的文章.我读过JavaTM Native Interface Programmer的指南和规范.9.5 Peer Classes有一个解决方案来处理它.

  • 链接已经死了 - 看起来像Oracle把内容放下了.有几个带镜像的网站,或者您可以使用archive.org:http://web.archive.org/web/20070101174413/http://java.sun.com/docs/books/jni/ (2认同)