возвращение массива из C в Java с помощью SWIG - PullRequest
6 голосов
/ 16 сентября 2011

У меня есть функция C, подобная этой:

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

Я написал это специально для Swig, поскольку

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

вызывает проблемы, поскольку карты типов SWIG недостаточно умнысвязать data_len с возвращаемым значением.

В Java я хочу иметь возможность вызывать эту функцию следующим образом:

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

Но я не могу понять, как получить массиввыходной параметр, чтобы стать возвращаемым значением.С Ruby и Python это прекрасно работает, так как SWIG для этих языков поддерживает возврат выходных параметров в качестве возвращаемых значений (поскольку языки могут иметь несколько возвращаемых значений).

Как я могу заставить это работать с Java?

1 Ответ

9 голосов
/ 12 мая 2012

Я собрал следующий файл заголовка теста, чтобы продемонстрировать проблему:

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

Я поговорю с файлом модуля, который я написал, он начинается довольно стандартно:

%module test

%{
#include "test.h"
%}

Затем мы устанавливаем карту типов для аргумента data_len. Он не должен быть видимым на стороне Java, так как длина будет известна массиву, но нам нужно организовать некоторое хранилище, чтобы указатель указывал на него, и мы гарантируем, что он длится достаточно долго, чтобы мы могли прочитать его позже при возврате массива в Java тоже.

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

Затем мы хотим, чтобы SWIG использовал short[] на стороне Java для типа возвращаемого значения:

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

и jshortArray на стороне JNI - нет необходимости создавать тип прокси, поэтому мы просто передаем возвращаемое значение напрямую:

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

Наконец, мы создаем карту типов, которая собирается создать новый массив, с размером, основанным на длине, возвращаемой функцией, и копируем полученный результат в массив Java для нас. При необходимости мы должны free() реальный массив результатов здесь, но в моем примере он был статически размещен, поэтому его не нужно освобождать.

%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
}

Наконец, мы включаем заголовочный файл для SWIG для переноса, используя только что написанные карты типов:

%include "test.h"

Я проверил это с помощью:

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

Который произвел:

1
2
3
4
5

Для справки вы могли бы обернуть:

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

также, хотя, если бы у вашей функции был способ запрашивать размер без установки массива, вы могли бы обернуть это немного умнее, выделив массив правильного размера на стороне Java. Для этого вам нужно написать промежуточную функцию в Java, которая запрашивает размер, настроить вызов и затем вернуть полученный массив. Это позволит вам использовать GetShortArrayElements / ReleaseShortArrayElements для потенциально 0 вызовов копирования.

Это будет работать, потому что массивы в Java в основном передаются по ссылке, например ::1010 *

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]);
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...