2016-05-24 9 views
5

Also muss ich JNI verwenden, um eine C-Funktion von Java aufzurufen. Ich konnte dies erfolgreich machen, wenn ich verschiedene Datentypen übergeben habe (native Variablen, Header-Datei, shared library, blah blah), aber ich kann es nicht mit einem Byte-Array arbeiten lassen. Hier ist meine C-Funktion:Wie kann ich Java Native Interface verwenden, um ein Byte-Array in eine C-Funktion zu übergeben, die ein char * als Argument verwendet?

#include <stdio.h> 
void encrypt(int size, unsigned char *buffer); 
void decrypt(int size, unsigned char *buffer); 

void encrypt(int size, unsigned char *buffer){ 
    for(int i=0; i<size; i++){ 
     unsigned char c = buffer[i]; 
     printf("%c",c); 
    } 
} 
void decrypt(int size, unsigned char *buffer){ 
    for(int i=0; i<size; i++){ 
     unsigned char c = buffer[i]; 
     printf("%c",c); 
    } 
} 

Und hier ist mein Java-Code (Ich verstehe, dass, nachdem eine Header-Datei von dieser machen, ich habe die C-Funktion Erklärungen des JNI-Code in der Header-Datei ersetzen)

class Tester{ 
    public native void encrypt(int size, char *buffer); 
    public native void decrypt(int size, char *buffer); 
    static{ 
    System.loadLibrary("buffer"); 
    { 
    public static void main(String[] args){ 
     Tester test = new Tester(); 
     String hello = "hello"; 
     byte[] byteHello = hello.getBytes(); 
     test.encrypt(5,byteHello); 
     test.decrypt(5,byteHello); 
    } 
} 

Ich bekomme, dass der char * -Typ in Java nicht unterstützt wird und deshalb bekomme ich einen Fehler beim Kompilieren. Vielleicht sollte ich den Typ in Java auf char [] ändern? Wie auch immer, mein Ziel ist es, ein Byte-Array in Java in meine C-Funktion zu übergeben, durch das Byte-Array zu iterieren und jedes Element auszudrucken.

+0

Die Java '' 'char''' und C' '' char''' Typen sind inkompatibel, es wäre wahrscheinlich besser das '' 'Byte []' '' an C zu übergeben und dann jedes Element zu konvertieren Anforderung –

+0

"Wie kann ich Java Native Interface verwenden, um ein Byte-Array in eine C-Funktion zu übergeben, die ein char * als Argument verwendet?" - Sie können nicht, aber Sie können ein Byte-Array in eine C-Funktion übergeben, die ein Java-Byte-Array als Argument verwendet. – immibis

Antwort

6

Die Java char und C char Typen sind inkompatibel, es wäre wahrscheinlich besser, die byte[] an C zu übergeben und dann jedes Element bei Bedarf zu konvertieren.


Etwas in dieser Richtung:

Main.java:

//...Code to load library... 

public static void main(String[] args) { 
    passBytes("hello".getBytes()); 
} 

public static native void passBytes(byte[] bytes); 

Main.c:

#include "Main.h" // Main.h is generated 

JNIEXPORT void JNICALL Java_Main_passBytes 
    (JNIEnv *env, jclass clazz, jbyteArray array) { 
    unsigned char* buffer = (*env)->GetByteArrayElements(env, array, NULL); 
    jsize size = (*env)->GetArrayLength(env, array); 

    for(int i = 0; i < size; i++) { 
     printf("%c", buffer[i]); 
    } 

    (*env)->ReleaseByteArrayElements(env, array, buffer, JNI_ABORT); 
} 

jbyteArray ist nichts mehr als ein Stub-Typ, definiert in jni.h:

struct _jobject; 
typedef struct _jobject *jobject; 
typedef jobject jarray; 
typedef jarray jbyteArray; 

Es enthält eigentlich keine Daten. Es ist mehr oder weniger nur eine Speicheradresse.

Um die Elemente daraus zu erhalten, geben wir sie an GetByteArrayElements weiter (da der Typ byte[] war), die die VM dann auffordern kann, die Elemente in einem C-artigen Array abzurufen. (Es könnte oder könnte nicht eine Kopie machen. Siehe doc)

Das gleiche gilt für die Array-Länge.

Um der VM zu sagen, sind wir mit dem Array fertig. Wir rufen ReleaseArrayElements.

Auch ist jbyte als signed char definiert, so dass nur das Ergebnis der GetByteArrayElements als unsigend char* anstelle von jbyte* ist in diesem Fall sicher.

+0

Ein bisschen mehr Erklärung würde dies eine bessere Antwort geben. Eine Kopie von Ihrem Kommentar wäre ein guter Anfang, aber es wäre auch erwähnenswert, dass ein Java-Array, wie es von einer nativen Methode empfangen wird, * kein * C-Array ist.Sie müssen die entsprechende JNI-Funktion verwenden, um davon ein tatsächliches C-Array zu erhalten (wie Sie demonstrieren), und das stellt einige zusätzliche Anforderungen an die gesamte native Methodenimplementierung. –

+0

@JohnBollinger Danke für den Vorschlag. Ich nahm an, dass OP das meiste schon wusste. Aber irgendwie vergesse ich manchmal andere Leute das auch zu lesen;) –

+1

Die Bedeutung der Release * -Funktionen besteht darin, die Objekte im JVM-Heap zu lösen. Die Array-Elemente werden nicht notwendigerweise durch Get * kopiert, und daher vermeidet JNI_ABORT nicht notwendigerweise das Modifizieren des JVM-Arrays; Es spart nur Zeit _wenn es eine Kopie gab .. –