J'ai quelques fonctions C que j'appelle via JNI qui prennent un pointeur vers une structure, et quelques autres fonctions qui alloueront/libéreront un pointeur vers le même type de structure afin qu'il soit un peu plus facile de gérer mon wrapper . Étonnamment, la documentation JNI en dit très peu sur la façon de gérer les structures C.
Mon fichier d'en-tête C ressemble à ceci:
typedef struct _MyStruct {
float member;
} MyStruct;
MyStruct* createNewMyStruct();
void processData(int *data, int numObjects, MyStruct *arguments);
Le fichier wrapper JNI C correspondant contient:
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);
}
... et enfin, la classe Java Java correspondante:
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);
}
}
Malheureusement, ce code plante la JVM juste après avoir appuyé sur createNewMyStruct()
. Je suis un peu nouveau pour JNI et je n'ai aucune idée du problème.
Edit: Je dois noter que le code C est très Vanilla C, est bien testé et a été porté à partir d'un projet iPhone fonctionnel. En outre, ce projet utilise le cadre Android NDK, qui vous permet d'exécuter du code C natif à partir d'un projet Android depuis JNI. Cependant, je ne le fais pas). pense que c'est strictement un problème NDK ... cela ressemble à une erreur de configuration/initialisation JNI de ma part.
Vous devez créer une classe Java avec les mêmes membres que C struct, et les "mapper" dans le code C via les méthodes env-> GetIntField, env-> SetIntField, env-> GetFloatField, env-> SetFloatField, et ainsi de suite - en bref, beaucoup de travail manuel, j'espère qu'il existe déjà des programmes qui le font automatiquement: JNAerator ( http://code.google.com/p/jnaerator ) et SWIG ( http://www.swig.org/ ). Les deux ont leurs avantages et leurs inconvénients, à vous de choisir.
Il se bloque car Java_com_myorg_MyJavaClass_createNewMyStruct
Est déclaré pour renvoyer jobject
, mais renvoie en fait struct MyStruct
. Si vous avez exécuté cela avec CheckJNI activé, la fonction VM se plaindrait fort et s'interromprait. Votre fonction processData()
va également être assez bouleversée par ce qu'elle reçoit _ arguments
.
Un jobject
est un objet sur le tas managé. Il peut contenir des éléments supplémentaires avant ou après les champs déclarés, et les champs n'ont pas besoin d'être disposés en mémoire dans un ordre particulier. Vous ne pouvez donc pas mapper une structure C au-dessus d'une classe Java.
La façon la plus simple de gérer cela était identifiée dans une réponse précédente: manipuler le jobject
avec les fonctions JNI. Allouez les objets de Java ou avec NewObject
, Get
/Set
les champs d'objet avec les appels appropriés.
Il existe différentes façons de "tricher" ici. Par exemple, vous pouvez inclure un byte[]
Dans votre Java contenant sizeof(struct MyStruct)
octets, puis utiliser GetByteArrayElements
pour obtenir un pointeur vers Un peu moche, surtout si vous voulez accéder aux champs du côté Java aussi.
La structure C est la collection de variables (certaines sont des pointeurs de fonction). Passer à Java n'est pas une bonne idée. En général, c'est le problème de savoir comment passer un type plus complexe à Java, comme un pointeur.
Dans le livre JNI, pour conserver le pointeur/la structure en natif et exporter la manipulation vers Java est recommandé. Vous pouvez lire quelques articles utiles. Guide et spécification du programmeur d'interface native JavaTM J'ai lu. 9.5 Classes de pairs ai une solution pour y faire face.
Ce n'est pas une solution idéale, mais cela peut vous faire gagner un peu de temps et cela vous donnera au moins un squelette que vous pouvez modifier. Cette fonctionnalité pourrait être ajoutée à un IDE, mais sans une grande demande, cela ne se produira probablement pas. La plupart des IDE ne prennent même pas en charge les projets de langues mixtes, sans parler de les faire se parler.