2012-06-08 10 views
5

Ho file h campione come qui di seguito:Come passare la matrice (array di lungo in java) da Java a C++ utilizzando Swig

class Test 
{ 
public: 
     void SelectValues(long long values[]) 
}; 

ho usato SWIG e ha creato un'interfaccia JNI da sotto lima .i

%module MyLib 
%include "carrays.i" 
%array_functions(long long, long_long_array) 


%{ 
    #include "Test.h" 
%} 

/* Let's just grab the original header file here */ 
%include <windows.i> /*This line is used for calling conventions*/ 
% include "Test.h" 

Quando creo metodo Java si crea come:

public void SelectValues(SWIGTYPE_p_long_long includeKeys) 

anche per il file JNI sta prendendo argomento come jlongArray ma prendendo semplicemente il jlong. A causa di questo problema non riesco a creare array di tipo long long[]={1L,2L} e passarlo al metodo Java sopra per chiamare il metodo JNI appropriato.

Voglio che SWIG generi un'interfaccia in modo tale da poter passare sopra l'array menzionato al mio metodo C++.

Ho letto this question, ma non mi ha aiutato a vedere come passare un array da Java a C++.

+0

il 'jlong' che hai visto sul lato JNI è come SWIG avvolge tutto ciò che non è un tipo primitivo. – Flexo

risposta

2

Quello che hai fatto qui con array_functions è corretto e utilizzabile, ma è incentrato sul wrapping del codice C++ direttamente e non utilizzerà un array Java sottostante. Si può usare con qualcosa di simile:

SWIGTYPE_p_long_long array = MyLib.new_long_long_array(100); // new array with 100 elements. 
for (int i = 0; i < 100; ++i) { 
    long_long_array_setitem(array, i, i); 
} 
new Test().SelectValues(array); 

dove array è solo un proxy per un "vero" C++ pezzo di memoria che si può leggere/scrivere dal lato Java e passare alle funzioni avvolti.

Sto supponendo dalla tua domanda che sei interessato a farlo sentire più "naturale" sul lato Java. SWIG fornisce anche array_class che avvolge un array in modo simile, ma come un oggetto appropriato piuttosto che una raccolta di funzioni statiche. Per esempio se è stato modificato il file interfaccia da utilizzare al posto di array_class(long long, LongLongArray)array_functions si può fare:

LongLongArray array = new LongLongArray(100); 
for (int i = 0; i < 100; ++i) { 
    array.setitem(i,i); 
} 
new Test().SelectValues(array.cast()); 

Si può effettivamente fare SWIG fare di più con pochi typemaps se si vuole. La tua classe di esempio non prende una lunghezza in SelectValues quindi suppongo che tu stia terminando la matrice 0, sebbene tu possa ugualmente superare la lunghezza con alcune semplici modifiche.

(Per comodità ho %inline D tua classe per ridurre il numero di file e ha aggiunto un'implementazione manichino di esso per le prove)

%module MyLib 

%{ 
#include <iostream> 
%} 

%typemap(jtype) long long values[] "long[]" 
%typemap(jstype) long long values[] "long[]" 
%typemap(javain) long long values[] "$javainput" 
%typemap(jni) long long values[] "jlongArray" 
%typemap(in) long long values[] { 
    jboolean isCopy; 
    $1 = JCALL2(GetLongArrayElements, jenv, $input, &isCopy); 
} 

%inline %{ 
class Test 
{ 
public: 
    void SelectValues(long long values[]) { 
    while (*values) { 
     std::cout << *values++ << "\n"; 
    } 
    } 
}; 
%} 

Qui abbiamo detto che sia lo SWIG classe proxy genera e la classe JNI esso genererà sta funzionando con long[], cioè una matrice Java. Non abbiamo bisogno di fare nulla nella conversione da Java Proxy a Java JNI, quindi la typemap javain è solo un passaggio dritto. Sul lato C++ del JNI è un jlongArray, che abbiamo anche specificato in un'altra typemap.

Abbiamo poi bisogno di un in typemap di organizzare la conversione da jlongArray a long long[] nella parte C++ - c'è una sola chiamata JNI per questo e non ci importa se si tratta di una copia o la memoria reale dalla JVM che finiamo utilizzando.(Si potrebbe preoccuparsi se si voleva modificare i risultati e rendere più visibile di nuovo dentro Java per esempio)

Ho provato questo con:

public class run { 
    public static void main(String[] argv) { 
    System.loadLibrary("mylib"); 
    long arr[] = {100,99,1,0}; // Terminate with 0! 
    new Test().SelectValues(arr); 
    } 
} 

Il che ha fatto esattamente come ci si spera.

+0

Se non si desidera utilizzare 0 per terminare gli array, è necessario modificare SelectValues ​​in qualcosa come: 'void SelectValues ​​(long long values ​​[], size_t len);' - Posso aggiungerlo alla mia risposta se volere. – Flexo

+0

Ho aggiunto quell'esempio alla fine: http://stackoverflow.com/q/11584599/168175 – Flexo

Problemi correlati