2011-09-24 2 views
10

J'utilise JNI pour transmettre des données entre C++ et Java. Je dois passer un type « long », et je le fais en utilisant quelque chose comme:Coulée d'un type long C++ à un JNI jlong ​​

long myLongVal = 100; 
jlong val = (jlong)myLongVal; 
CallStaticVoidMethod(myClass, "(J)V", (jvalue*)val); 

Cependant en Java, lorsque le paramètre « long » est récupéré, il obtient récupéré un nombre négatif comme très important. Qu'est-ce que je fais mal?

+2

'long! = Jlong' peut-être? – quasiverse

+0

Curieusement, Java a continué à obtenir 4294967297 quand je lui ai passé une valeur de "1" à travers JNI. Ce nombre est un nombre de Fermat. Cela semble terriblement coïncident. Si quelqu'un a des idées sur la raison pour laquelle cette valeur particulière a été vue, je serais intéressé à l'entendre. De retour sur le sujet, lancer ma longueur comme '(jlong) value' a permis à Java/JNI de l'analyser à la valeur correcte de 1. – StockB

+1

4294967297 est (1 << 32) + 1 – samgak

Répondre

12

Lorsque vous passez un jlong ​​(qui est 64 bits) en tant que pointeur (qui est, très probablement, 32 bits), vous perdez nécessairement des données. Je ne sais pas quelle est la convention, mais vous pouvez soit essayer ceci:

CallStaticVoidMethodA(myClass, "(J)V", (jvalue*)&val); //Note address-of! 

ou ceci:

CallStaticVoidMethod(myClass, "(J)V", val); 

Il est ...A méthodes qui prennent un tableau jvalue, les méthodes non-Postfix prennent équivalents C à scalaire Types Java.

Le premier extrait est quelque peu dangereux; mieux, si plus bavard, alternative serait:

jvalue jv; 
jv.j = val; 
CallStaticVoidMethodA(myClass, "(J)V", &jv); 

Sur certains archtectures CPU exotiques, les exigences d'alignement pour jlong variables et jvalue syndicats peuvent être différents. Lorsque vous déclarez une union explicitement, le compilateur s'en charge.

Notez également que le type de données C++ long est souvent de 32 bits. jlong ​​est 64 bits, sur les plates-formes 32 bits, l'équivalent C non standard est long long ou __int64.

+3

" C++ long est 32-bit aussi "- - sur certaines architectures, pas sur d'autres. x64 Linux utilise généralement 64 bits de long. long long n'est pas disponible partout non plus (c'est une extension IIRC). –

+1

C'est vrai, ça. Je vais ajouter une qualification. –

+0

Merci pour votre réponse - malheureusement, j'ai essayé les deux approches suggseted et le paramètre apparaît encore tronqué lorsqu'il est récupéré en Java, j'ai également essayé avec int et float types en plus de long :(Bizarrement le suivant * fonctionne *, et seulement int types (bien que cela n'a pas de sens) 'int someInt = 100; CallStaticVoidMethod (myClass," (I) V ", (jvalue *) (jint) someInt);' –

3
CallStaticVoidMethod(myClass, "(J)V", (jvalue*)val); 

Ceci est un comportement indéfini. Vous lancez un entier pour être un pointeur. Ce n'est pas un pointeur. Vous devez, à tout le moins, passer l'adresse . Ce code serait automatiquement écrasé sur la plupart des plates-formes.

+0

vous avez absolument raison - je devrais prendre l'adresse, mais cela ne fonctionne toujours pas pour moi (indépendamment de float, int ou long type, comme j'ai essayé tous ceux-ci.) Bizarrement, les travaux suivants, et seulement pour les types int (si cela n'a aucun sens) 'int someInt = 100; CallStaticVoidMethod (myClass," (I) V " , (jvalue *) (jint) someInt) " –