Richtige Interaktion mit Arrays mithilfe von SWIG

Ich bin ein bisschen verloren mit Typemaps in Swig und wie man Arrays verwendet. Ich habe ein funktionierendes Beispiel vorbereitet, das Arrays zwischen Java und C unter Verwendung von Swig verwendet, aber ich weiß nicht, ob es der richtige Weg ist, dies zu tun.

Grundsätzlich möchte ich ein Byte-Array übergebenbyte[] von java nach c als zeichen * `+ es ist größe, modifiziere es in c und sieh dir die veränderungen in java an und erstelle ein array in c und verwende es in Java.

Ich habe mir diese Fragen angesehen:So übergeben Sie Array (Array von Long in Java) mit Swig von Java an C ++, Übergeben Sie ein Array als Zeiger + Größe oder Bereich an eine umschlossene Funktion, Wie kann ich Swig veranlassen, einen char * -Puffer, der in C geändert wurde, korrekt als Java Something-or-Other zu verpacken?

Und tatsächlich haben wir die Lösungen als Leitfaden verwendet, um das Beispiel zu machen.

Das ist mein Code in der Datei arrays.h:

#include <iostream>

bool createArray(signed char ** arrCA, int * lCA){
    *lCA = 10;
    *arrCA = (signed char*) calloc(*lCA, sizeof(signed char));

    for(int i = 0; i < *lCA; i++){
        (*arrCA)[i] = i;
    }

    return *arrCA != NULL;
}

bool readArray(const signed char arrRA[], const int lRA){
    for(int i = 0; i < lRA; i++){
        std::cout << ((unsigned int) arrRA[i]) << " ";
    }
    std::cout << std::endl;
    return true;
}

bool modifyArrayValues(signed char arrMA[], const int lMA){
    for(int i = 0; i < lMA; i++){
        arrMA[i] = arrMA[i] * 2;
    }
    return true;
}


bool modifyArrayLength(signed char arrMALIn[], int lMALIn, signed char ** arrMALOut, int * lMALOut){

    *lMALOut = 5;
    *arrMALOut = (signed char*) calloc(*lMALOut, sizeof(signed char));

    for(int i = 0; i < *lMALOut; i++){
        (*arrMALOut)[i] = arrMALIn[i];
    }
    return true;
}

Dies ist die .i-Datei für swig (arrays.i):

%module arrays

%{
    #include "arrays.h"
%}

%typemap(jtype) bool createArray "byte[]"
%typemap(jstype) bool createArray "byte[]"
%typemap(jni) bool createArray "jbyteArray"
%typemap(javaout) bool createArray { return $jnicall; }
%typemap(in, numinputs=0) signed char ** arrCA (signed char * temp) "$1=&temp;"
%typemap(in, numinputs=0) int * lCA (int l) "$1=&l;"
%typemap(argout) (signed char ** arrCA, int * lCA) {
    $result = JCALL1(NewByteArray, jenv, *$2);
    JCALL4(SetByteArrayRegion, jenv, $result, 0, *$2, (const jbyte*) *$1);
}
%typemap(out) bool createArray {
    if (!$1) {
        return NULL;
    }
}


%typemap(jtype) (const signed char arrRA[], const int lRA) "byte[]"
%typemap(jstype) (const signed char arrRA[], const int lRA) "byte[]"
%typemap(jni) (const signed char arrRA[], const int lRA) "jbyteArray"
%typemap(javain) (const signed char arrRA[], const int lRA) "$javainput"

%typemap(in,numinputs=1) (const signed char arrRA[], const int lRA) {
  $1 = JCALL2(GetByteArrayElements, jenv, $input, NULL);
  $2 = JCALL1(GetArrayLength, jenv, $input);
}

%typemap(freearg) (const signed char arrRA[], const int lRA) {
  // Or use  0 instead of ABORT to keep changes if it was a copy
  JCALL3(ReleaseByteArrayElements, jenv, $input, $1, JNI_ABORT); 
}


%typemap(jtype) (signed char arrMA[], const int lMA) "byte[]"
%typemap(jstype) (signed char arrMA[], const int lMA) "byte[]"
%typemap(jni) (signed char arrMA[], const int lMA) "jbyteArray"
%typemap(javain) (signed char arrMA[], const int lMA) "$javainput"

%typemap(in, numinputs=1) (signed char arrMA[], const int lMA) {
    $1 = JCALL2(GetByteArrayElements, jenv, $input, NULL);
    $2 = JCALL1(GetArrayLength, jenv, $input);
}

%typemap(freearg) (signed char arrMA[], const int lMA) {
  JCALL3(ReleaseByteArrayElements, jenv, $input, $1, 0); 
} 

%typemap(jtype) (signed char arrMALIn[], int lMALIn) "byte[]"
%typemap(jstype) (signed char arrMALIn[], int lMALIn) "byte[]"
%typemap(jni) (signed char arrMALIn[], int lMALIn) "jbyteArray"
%typemap(javain) (signed char arrMALIn[], int lMALIn) "$javainput"

%typemap(in, numinputs=1) (signed char arrMALIn[], int lMALIn) {
    $1 = JCALL2(GetByteArrayElements, jenv, $input, NULL);
    $2 = JCALL1(GetArrayLength, jenv, $input);
}

%typemap(freearg) (signed char arrMALIn[], int lMALIn) {
    JCALL3(ReleaseByteArrayElements, jenv, $input, $1, JNI_ABORT); 
}

%typemap(jtype) bool modifyArrayLength "byte[]"
%typemap(jstype) bool modifyArrayLength "byte[]"
%typemap(jni) bool modifyArrayLength "jbyteArray"
%typemap(javaout) bool modifyArrayLength { return $jnicall; }
%typemap(in, numinputs=0) signed char ** arrMALOut (signed char * temp) "$1=&temp;"
%typemap(in, numinputs=0) int * lMALOut (int l) "$1=&l;"
%typemap(argout) (signed char ** arrMALOut, int * lMALOut) {
    $result = JCALL1(NewByteArray, jenv, *$2);
    JCALL4(SetByteArrayRegion, jenv, $result, 0, *$2, (const jbyte*) *$1);
}
%typemap(out) bool modifyArrayLength {
    if (!$1) {
        return NULL;
    }
}


%include "arrays.h"

Und zum Schluss den Java-Code zum Testen:

public class Run{

    static {
        System.loadLibrary("Arrays");
    }

    public static void main(String[] args){

        byte[] test = arrays.createArray();

        printArray(test);       

        arrays.readArray(test);

        arrays.modifyArrayValues(test);

        printArray(test);

        byte[] test2 = arrays.modifyArrayLength(test);

        printArray(test2);

    }

    private static void printArray(byte[] arr){

        System.out.println("Array ref: " + arr);

        if(arr != null){
            System.out.println("Array length: " + arr.length);

            System.out.print("Arrays items: ");

            for(int i =0; i < arr.length; i++){
                System.out.print(arr[i] + " ");
            }
        }
        System.out.println();
    }
}

Das Beispiel funktioniert, aber ich bin mir nicht sicher, ob das der richtige Weg ist. Ich meine:

Gibt es einen einfacheren Weg, um das gleiche Ergebnis zu erzielen?

Hat dieser Code Speicherverluste (auf der einen Seite glaube ich, dass es da ist, weil ich ein Calloc mache, aber ich es nicht freigebe, aber auf der anderen Seite übergebe ich es an die SetByteArrayRegion, also würde das Freigeben möglicherweise einen Fehler verursachen)?

kopiert die SetByteArrayRegion die Werte oder nur die Referenz? Zum Beispiel, wenn anstelle eines Callocs ein Array aus einem C ++ - Objekt per Referenz abgerufen wird, das beim Verlassen des Gültigkeitsbereichs zerstört wird?

Wird das an Java zurückgegebene Array beim Nullen korrekt freigegeben?

Gibt es eine Möglichkeit, anzugeben, von wo bis wo eine Typzuordnung angewendet wird? Ich meine, im .I-Code habe ich eine Typzuordnung für jede Funktion bereitgestellt, wobei ich denke, dass ich einige von ihnen wiederverwenden könnte, aber wenn es andere Funktionen mit denselben gäbe Parameter, die ich nicht tippen möchte. Wie kann ich das tun? Möglicherweise kann ich den Parameternamen der Funktionen nicht ändern.

Ich habe die in dieser Frage beschriebene Möglichkeit von carrays.i gesehenWie übergebe ich mit Swig Arrays von Java an C ++?, aber das bedeutet, dass ich, wenn die Größe des Arrays 1000 Elemente beträgt und ich es über einen Java-Socket senden oder einen String daraus erstellen möchte, für jedes Array-Element 1 JNI-Aufruf ausführen muss. Und ich möchte eigentlich einebyte[] Auf der Java-Seite gibt es keine Reihe von Funktionen für den Zugriff auf das zugrunde liegende Array, sodass bereits vorhandener Code ohne Änderungen funktioniert.

Kontext: Der Grund, warum ich dies erreichen möchte, ist, dass es eine Bibliothek gibt, die einige Funktionen hat, aber der wichtige Teil hier ist, dass es erlaubt, Daten aus der Bibliothek unter Verwendung der Google Protocols Buffers zu importieren und zu exportieren. Der Code für diese Frage sieht also so aus:

class SomeLibrary {

  bool export(const std::string & sName, std::string & toExport);

  bool import(const std::string & sName, const std::string & toImport);

}

Die Sache ist, dass Protobuf in C ++ std :: string verwendet, um die Daten zu speichern, aber diese Daten sind binär, so dass sie nicht als normale Java-Zeichenfolge zurückgegeben werden können, da sie abgeschnitten werden, mehr davon inSwig: Rückgabetyp std :: string (binär) in Java-Byte konvertieren [].

Meine Idee ist es also, zu Java zurückzukehrenbyte[] für den serialisierten Protobuf (wie auch die Java-Version der Protokollpuffer) und akzeptierenbyte[] zum analysieren von protobufs. Um zu vermeiden, zu bekommenSWIGTYPE_p_std_string Im zweiten Argument des Exports und mit String für das zweite Argument des Imports haben y beide Funktionen mit% extend wie folgt umbrochen:

%extend SomeLibrary{

  bool export(const std::string & sName, char ** toExportData, int * toExportLength);

  bool import(const std::string & sName, char * toImportData, int toImportLength);

}

Und jetzt sollte ich in der Lage sein, die Typemaps zu machen.

Aber um allgemeiner zu sein, fragte ich nach dem General der Manipulation von Arrays von Java nach SWIG,haben das native Javabyte[].

Antworten auf die Frage(2)

Ihre Antwort auf die Frage