Comment passer C les structures d'avant en arrière pour le code Java dans JNI?
J'ai quelques fonctions C qui je suis en appel par JNI qui prennent un pointeur sur une structure, et quelques autres fonctions qui allouera/libérer un pointeur vers le même type de structure, de sorte qu'il est un peu plus facile à traiter avec mon wrapper. Étonnamment, la JNI documentation dit très peu de choses sur la façon de traiter avec les structures C.
Mon C fichier d'en-tête ressemble à ceci:
typedef struct _MyStruct {
float member;
} MyStruct;
MyStruct* createNewMyStruct();
void processData(int *data, int numObjects, MyStruct *arguments);
Le correspondant JNI C wrapper fichier 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 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 d'accidents de la JVM juste après frapper createNewMyStruct()
. Je suis un peu nouveau pour JNI et n'ont aucune idée de ce que le problème pourrait être.
Modifier: je tiens à noter que le code C est très vanille C, est bien testé et a été porté à partir d'un iPhone de projet. Aussi, ce projet est à l'aide de l'Android NDK cadre, ce qui vous permet d'exécuter le code C code à partir d'un projet Android à partir de l'intérieur de JNI. Cependant, je ne pense pas que c'est strictement un NDK question... il semble qu'un JNI programme d'installation/de l'initialisation erreur de ma part.
- Quelque chose de plus précis à propos de l'erreur? Un message d'erreur?
- Nope, c'est juste accidents de la JRE. C'est un écueil à propos des relations avec JNI...
- Le CheckJNI fonctionnalité a été ajoutée pour trouver le code commun des erreurs avant qu'ils ne deviennent Heisenbugs. Il est activé par défaut dans l'émulateur. Voir la jni-conseils et incorporé-vm-contrôle docs android.git.kernel.org/?p=platform/... pour plus d'informations sur l'activation sur un appareil.
- Jetez un oeil à la JNA (et voir aussi l'article).
- Vous pouvez également passer nio.DirectByteBuffers par JNI et d'analyser la mémoire sur l'île de Java, en utilisant par exemple github.com/marc-christian-schulze/structs4java
Vous devez vous connecter pour publier un commentaire.
Vous devez créer une classe Java avec les mêmes membres que C struct, et "carte" dans le code C par l'intermédiaire des méthodes env->GetIntField, env->SetIntField, env->GetFloatField, env->SetFloatField, et ainsi de suite, bref, beaucoup de travail manuel, je l'espère, 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 inconvénients, le choix est à vous.
C'est s'écraser parce que
Java_com_myorg_MyJavaClass_createNewMyStruct
est déclarée pour retournerjobject
, mais est en fait le retour structMyStruct
. Si vous avez exécuté cette avec CheckJNI activé, la machine virtuelle puisse se plaindre bruyamment et d'abandon. VotreprocessData()
fonction va également être assez contrarié à propos de ce qu'il obtient remisarguments
.Un
jobject
est un objet sur le tas managé. Il peut avoir des trucs supplémentaires avant ou après la déclaration de champs, et les champs n'ont pas à être mises en mémoire dans un ordre particulier. Si vous ne pouvez pas mapper un struct C sur le haut d'une classe Java.La façon la plus simple de traiter avec cela a été indiqué dans une précédente réponse: manipuler les
jobject
avec JNI fonctions. Allouer les objets de Java ou avecNewObject
,Get
/Set
les champs d'objet avec des appels appropriés.Il y a différentes manières de "tricher" ici. Par exemple, vous pourriez inclure une
byte[]
dans votre objet Java qui détientsizeof(struct MyStruct)
octets et ensuite utiliserGetByteArrayElements
pour obtenir un pointeur vers elle. Un peu moche, surtout si vous souhaitez accéder aux champs de la Java côté.Structure C est la collection de variables (certains sont de pointeur de fonction). Passer à java n'est pas une bonne idée. En général, c'est le problème de la manière de passer les plus complexes de type de java, comme pointeur.
Dans JNI livre, pour garder le pointeur/structure native et l'exportation de manipulation de java est recommandé. Vous pouvez lire quelques articles utiles. La Java Native Interface Guide du Programmeur et le cahier des charges J'ai lu. 9.5 Classes De Pairs avez une solution pour traiter avec elle.
Ce n'est pas une solution idéale, mais il peut vous faire économiser un peu de temps, et il va au moins vous donner un squelette que vous pouvez modifier. Cette fonctionnalité peut être ajoutée à un IDE, mais sans une forte demande, il ne sera probablement pas se produire. La plupart des IDEs ne supportent même mélangés les projets de langue, et encore moins d'avoir parler les uns aux autres.