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/).两者都有其优点和缺点,选择取决于你.
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端访问字段.
C结构是变量的集合(有些是函数指针).传递给java并不是一个好主意.一般来说,问题是如何将更复杂的类型传递给java,比如指针.
在JNI书中,建议将指针/结构保留为原生和导出操作到java.你可以阅读一些有用的文章.我读过JavaTM Native Interface Programmer的指南和规范.9.5 Peer Classes有一个解决方案来处理它.