2016-05-24 14 views
5

Quindi ho bisogno di usare JNI per chiamare una funzione C da java. Sono stato in grado di farlo con successo quando si passavano in diversi tipi di dati (creare le variabili native, il file di intestazione, la libreria condivisa, blah blah), ma non riuscivo a farlo funzionare con un array di byte. Ecco la mia funzione C:Come posso utilizzare Java Native Interface per passare un array di byte in una funzione C che accetta un char * come argomento?

#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); 
    } 
} 

Ed ecco il mio codice Java (Mi rendo conto che dopo aver fatto un file di intestazione da questo, devo sostituire le dichiarazioni di funzione C dal codice JNI nel file di intestazione)

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); 
    } 
} 

Ho capito che il tipo char * non è supportato in Java ed è per questo che sto ricevendo un errore nel tentativo di compilare. Forse dovrei cambiare il tipo in char [] in Java? Ad ogni modo, il mio obiettivo è essere in grado di passare un array di byte in Java nella mia funzione C, iterare attraverso l'array di byte e stampare ogni elemento.

+0

I tipi java '' 'char''' e C' '' char''' sono incompatibili, sarebbe probabilmente meglio passare il '' 'byte []' '' a C e quindi convertire ogni elemento su richiesta –

+0

"Come posso utilizzare Java Native Interface per passare un array di byte in una funzione C che accetta un char * come argomento?" - Non puoi, ma puoi passare un array di byte in una funzione C che accetta un array di byte Java come argomento. – immibis

risposta

6

I tipi Java char e C char non sono compatibili, sarebbe probabilmente meglio passare lo byte[] in C e quindi convertire ogni elemento su richiesta.


Qualcosa in questo senso:

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 è niente di più di un tipo di stub, definito in jni.h:

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

In realtà non contiene alcun dato. È più o meno solo un indirizzo di memoria.

Per ottenere gli elementi da esso lo passiamo a GetByteArrayElements (poiché il tipo era byte[]) che può chiedere alla VM di recuperare gli elementi in un array in stile C. (Potrebbe o non potrebbe fare una copia. Vedere documento)

Lo stesso viene fatto per la lunghezza dell'array.

Per dire alla VM che abbiamo finito con la matrice. Chiamiamo ReleaseArrayElements.

Inoltre, jbyte è definito come signed char, così appena usando il risultato di GetByteArrayElements come unsigend char* anziché jbyte* è sicuro in questo caso.

+0

Un po 'più di spiegazione renderebbe questa una risposta migliore. Una copia dal tuo commento sarebbe un buon inizio, ma vale anche la pena ricordare che un array Java come ricevuto da un metodo nativo è * non * un array C.È necessario utilizzare la funzione JNI appropriata per ottenere da essa un effettivo array C (come si dimostra) e ciò pone alcuni requisiti aggiuntivi sull'implementazione del metodo nativo complessivo. –

+0

@JohnBollinger Grazie per il suggerimento. Ho pensato che OP sapesse già la maggior parte di questo. Ma in qualsiasi modo, a volte dimentico che altre persone leggeranno anche questo;) –

+1

L'importanza delle funzioni di Release * è di sbloccare gli oggetti nell'heap JVM. Gli elementi dell'array non sono necessariamente copiati da Get * e quindi JNI_ABORT non necessariamente evita di modificare l'array JVM; Fa solo risparmiare tempo _if_ c'era una copia .. –

Problemi correlati