Используйте SWIG для обработки функции C, возвращающей указатель на массив структур в Java - PullRequest
1 голос
/ 15 декабря 2011

Я пытаюсь выяснить, какое изменение файла интерфейса SWIG необходимо для обработки getFoo возвращает указатель, который указывает на массив пользовательской структуры (sender_id_t). Без какого-либо специального кода интерфейса SWIG, я получаю только указатель на стороне Java. Как я могу превратить этот указатель во что-то, что я могу зациклить или перебрать (в Java), чтобы я мог получить каждое значение идентификатора sender_id_t? Ценю любые предложения.

C Состав:

typedef unsigned char id_v1_t[32];
typedef id_v1_t id_t;
%rename (Sample) sender_id_t_;
struct sender_id_t_ {
    id_t       id;
    uint32_t   phy_idx;
};

C Функция:

//This will return a pointer to an array of sender_id_t data.  The number of elements is retrieved from a separate call. 
sender_id_t* getFoo(resultset_t* resultset);

Исключение:

 [exec] test_wrap.c: In function `new_foo_array':
 [exec] test_wrap.c:785: error: invalid application of `sizeof' to incomplete type `sender_id_t_' 
 [exec] test_wrap.c: At top level:
 [exec] test_wrap.c:792: error: return type is an incomplete type
 [exec] test_wrap.c: In function `foo_array_getitem':
 [exec] test_wrap.c:793: error: invalid use of undefined type `struct sender_id_t_'
 [exec] test_wrap.c:793: error: dereferencing pointer to incomplete type
 [exec] test_wrap.c:793: warning: `return' with a value, in function returning void
 [exec] test_wrap.c: At top level:
 [exec] test_wrap.c:795: error: parameter `value' has incomplete type
 [exec] test_wrap.c: In function `foo_array_setitem':

1 Ответ

2 голосов
/ 16 декабря 2011

Самое простое решение для этого вообще не предполагает написания JNI - фактически это метод 2 .Поэтому я использовал carrays.i для предоставления очень простого интерфейса, а затем написал небольшой кусочек Java, чтобы сделать представление public более удобным и интуитивно понятным.Ключевым моментом является то, что вам нужно предоставить способ объединения знаний массива и его длины.Я собрал минимальный законченный пример, чтобы проиллюстрировать, что он возвращает массив Java, но он может одинаково работать для ArrayList или любой коллекции, которая вам нравится.

Во-первых, файл заголовка со встроенной реализацией длякомпактность:

#ifndef TEST_H
#define TEST_H

struct Foo {
   int v;
};

inline static struct Foo *getFoo() {
  static struct Foo r[] = {{0},{1},{2}};
  return r;
}

inline static unsigned short numFoo() {
  return 3;
}

#endif

Затем он оборачивается:

%module test

%{
#include "test.h"
%}

%include <carrays.i>
%array_functions(struct Foo, foo_array);

%rename(getFooImpl) getFoo;
%javamethodmodifiers getFoo() "private";
%javamethodmodifiers numFoo() "private";
%include "test.h"

%pragma(java) modulecode=%{
  public static Foo[] getFoo() {
    final int num = numFoo();
    Foo ret[] = new Foo[num];
    Foo result = getFooImpl();
    for (int i = 0; i < num; ++i) {
      ret[i] = foo_array_getitem(result, i);
    }
    return ret;
  }  
%}

Где мы переименуем getFoo() из заголовочного файла и сделаем его и соответствующий numFoo() privateдетали реализации.

Используя эти две частные функции, мы можем затем написать вещественное число, public Foo[] getFoo(), которое вызывает эти две функции, а затем копирует результаты в фактический массив известного размера.

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

public class main {
  public static void main(String[] argv) {
    System.loadLibrary("test");
    Foo[] foos = test.getFoo();
    System.out.println(foos[2].getV());
  }
}

На мой взгляд, это решение чище, чем соответствующий пример на основе JNI - его проще писать и труднее вводить ошибки, что делает его более удобным в обслуживании.Любой программист на Java или C, который смотрит на это, может в значительной степени увидеть, что происходит.Вероятно, это не намного хуже с точки зрения производительности и, вероятно, не будет большой частью времени на каком-то критическом пути - если тесты покажут, что это проблема, тогда все равно легко пойти по пути JNI позже.

Для полноты аспекта "make it private" вы также можете сделать что-то вроде:

%javamethodmodifiers foo_array_getitem "private";
%ignore foo_array_setitem;
%ignore delete_foo_array;
%ignore new_foo_array;
%include <carrays.i>
%array_functions(struct Foo, foo_array);

Чтобы скрыть все функции, которые генерируются макросом %array_functions.

...