2011-09-16 12 views
5

Mam funkcji C tak:powrocie tablicę z C do Javy z SWIG

void get_data(const obj_t *obj, short const **data, int *data_len); 

napisałem to tak specjalnie dla Swig, ponieważ

const short *get_data(const obj_t *obj, int *data_len); 

przyczyny kłopotów, jak typemaps łyk za nie są wystarczająco inteligentne, aby powiązać dane data z wartością zwracaną.

W Javie Chcę, aby móc wywołać tę funkcję tak:

short data[]= mylib.get_data(obj); 

Ale nie mogę dowiedzieć się, jak uzyskać parametr wyjściowy tablica stać się wartość zwracana. W Ruby i Pythonie działa to dobrze, ponieważ SWIG dla tych języków obsługuje zwracanie parametrów wyjściowych jako wartości zwracanych (ponieważ języki mogą mieć wiele wartości zwracanych).

Jak mogę to wykorzystać w Javie?

+0

Czy nadal szuka rozwiązania tego problemu? – Flexo

+0

Tak, nadal nie wiem jak to zrobić – paleozogt

+0

Odpowiedziałem na odpowiedź, która dokładnie odpowiada składni Java, o którą prosiłeś. Istnieje jednak możliwość odpowiedzi na oryginalną funkcję C, jeśli możesz zapytać o rozmiar bez wypełniania tablicy. Dodam to do mojej odpowiedzi, jeśli jesteś zainteresowany. – Flexo

Odpowiedz

7

I już ułożyła następujący plik nagłówka, aby wykazać problem:

typedef struct { } obj_t; 

const short *get_data(const obj_t *obj, int *data_len) { 
    (void)obj; 
    static short arr[] = {1,2,3,4,5}; 
    *data_len = sizeof(arr)/sizeof(*arr); 
    return arr; 
} 

Pogadamy za pośrednictwem pliku modułu pisałem, zaczyna dość standardowy:

%module test 

%{ 
#include "test.h" 
%} 

Następnie przygotowaliśmy typografię dla argumentu data_len. Nie musi być widoczna po stronie Java, ponieważ długość będzie znana przez tablicę, ale musimy ustawić trochę miejsca na wskazanie wskaźnika i upewniamy się, że trwa on wystarczająco długo, abyśmy mogli go przeczytać później przy zwracaniu tablicy do Javy.

%typemap(in,numinputs=0,noblock=1) int *data_len { 
    int temp_len; 
    $1 = &temp_len; 
} 

Następnie chcemy SWIG używać short[] na stronie Java dla Zwraca typ:

%typemap(jstype) const short *get_data "short[]" 
%typemap(jtype) const short *get_data "short[]" 

i jshortArray w boku JNI - nie ma potrzeby, aby skonstruować typ serwera proxy, więc po prostu przejść zwracana wartość prosto przez:

%typemap(jni) const short *get_data "jshortArray" 
%typemap(javaout) const short *get_data { 
    return $jnicall; 
} 

końcu tworzymy typemap że zamierza utworzyć nową tablicę o wielkości na podstawie długości wrócił z zabawy ction i skopiuj zwracany wynik do tablicy Java dla nas. W razie potrzeby powinniśmy tutaj uzyskać rzeczywistą tablicę wyników, ale w moim przykładzie została ona przydzielona statycznie, więc nie trzeba jej było zwalniać.

%typemap(out) const short *get_data { 
    $result = JCALL1(NewShortArray, jenv, temp_len); 
    JCALL4(SetShortArrayRegion, jenv, $result, 0, temp_len, $1); 
    // If the result was malloc()'d free it here 
} 

Wreszcie dołączyć plik nagłówkowy dla SWIG zawijać, korzystając z typemaps po prostu napisał:

%include "test.h" 

testowałem to z:

public class run { 
    public static void main(String argv[]) { 
    System.loadLibrary("test"); 
    obj_t obj = new obj_t(); 
    short[] result = test.get_data(obj); 
    for (int i = 0; i < result.length; ++i) { 
     System.out.println(result[i]); 
    } 
    } 
} 

który produkował:

 
1 
2 
3 
4 
5 

Dla porównania mogłeś owinięty:

void get_data(const obj_t *obj, short const **data, int *data_len); 

również choć jeśli funkcja miał sposób do kwerendy rozmiaru bez ustawiania tablicy można owinąć to nieco mądrzejszy przeznaczając tablicę prawidłowej wielkości na Jawie bok. Aby to zrobić, chciałbyś napisać funkcję pośredniczącą w Javie, która zapytała o rozmiar, skonfigurowała wywołanie, a następnie zwróciła wynikową tablicę. Umożliwi to użycie GetShortArrayElements/ReleaseShortArrayElements dla potencjalnie 0 kopiowania.

To działa, ponieważ tablice w Javie są zasadniczo przekazywane przez referencję, np .:

public class ret { 
    public static void foo(int arr[]) { 
    arr[0] = -100; 
    } 

    public static void main(String argv[]) { 
    int arr[] = new int[10]; 
    System.out.println(arr[0]); 
    foo(arr); 
    System.out.println(arr[0]); 
    } 
} 
+2

Dla wygody, kompletny plik interfejsu, który testowałem, znajduje się na mojej stronie pod adresem: http://static.lislan.org.uk/~ajw/javaarrout.i - jeśli ten link pęknie, odpowiedź nic nie straci, ponieważ może być odtworzone z samej odpowiedzi. – Flexo