Passer le pointeur de C à Java devient NULL

Je travaille sur une application Android pour x86 qui nécessite une certaine intégration avec C. J’ai utilisé swig / JNI pour faire l’affaire, et les choses se sont bien déroulées pour la plupart. Cependant, les pointeurs m’ont donné des erreurs.

Mon problème est que je suis capable de référencer avec succès des adresses de variable dans l’émulateur (ARM) mais que sur un périphérique (x86), les choses ne se passent pas aussi bien.

En utilisant l’exemple de ce lien , j’ai découvert que l’adresse de toute variable allouée en C devient NULL une fois que cette adresse a été transférée à Java. Par exemple…

JNI généré par Swig:

SWIGEXPORT jlong JNICALL Java_exampleJNI_new_1intp(JNIEnv *jenv, jclass jcls) { jlong jresult = 0 ; int *result = 0 ; (void)jenv; (void)jcls; result = (int *)new_intp(); LOGI("Result is %x", result); *(int **)&jresult = result; LOGI("JResult is %x", jresult); return jresult; } 

Fichier source contenant new_intp ():

 static int *new_intp() { return (int *) calloc(1,sizeof(int)); } 

J’ai des déclarations d’impression vérifiant la valeur de l’adresse telle qu’elle provient de C et passe à Java. Dans new_intp (), la nouvelle variable se voit atsortingbuer une adresse attrayante, mais une fois que cette valeur est retournée à JNI et convertie en jlong, elle passe à NULL.

En d’autres termes, *(int **)&jresult = result; fait que jresult soit à 0.

Pourquoi cela arrive-t-il? Existe-t-il une particularité de x86 qui empêche JNI de travailler avec des pointeurs? Ou est-ce parce que je le teste sur un périphérique physique plutôt que sur un émulateur?

Cordialement

Il me semble que cela pourrait être un problème d’endianisme.

 *(int **)&jresult = result; 

Si int correspond à 32 bits et jresult 64 bits, cela pourrait donner des résultats inattendus sur une architecture big-endian.

&jresult est un pointeur sur une valeur de 64 bits. Par conséquent, si vous le &jresult en une valeur de 32 bits, vous pointez l’adresse la plus basse des deux mots de 32 bits constitutifs. Dans un système big-endian, ce sera le mot le plus significatif. Ainsi, après avoir écrit un mot de 32 bits à l’extrémité la plus significative de la valeur de 64 bits, vous obtenez une valeur de 64 bits qui est 2 ^ 32 fois plus grande que celle que vous attendez.

Si votre appel LOGI traite le paramètre comme un LOGI 32 bits et le LOGI implicitement à partir d’une valeur de 64 bits, il donnera 0.

Pouvez-vous voir si cela fonctionne à la place?

 jresult = (jlong) result; 

En fait, il s’agit d’un problème de pointeur-aliasing . SWIG utilise des techniques de pointeur C à l’ancienne qui ne fonctionnent pas dans les nouveaux GCC lorsque l’optimisation est activée. Enfoui dans la documentation SWIG, il indique spécifiquement quoi faire :

Important

Si vous allez utiliser les optimisations activées avec gcc (par exemple -O2), assurez-vous également de comstackr avec -fno-ssortingct-aliasing. Les optimisations de GCC sont devenues plus agressives à partir de gcc-4.0 et donneront lieu à un code qui échouera si les optimisations de crénelage sont activées. Reportez-vous à la section Cartes de types C / C ++ vers Java pour plus de détails.