使用SWIG处理C函数返回Java中结构数组的指针

我想弄清楚需要什么SWIG接口文件更改才能处理getFoo返回一个指向自定义结构数组的指针(sender_id_t)。 没有任何特殊的SWIG接口代码,我只得到Java端的指针。 如何将该指针转换为可循环或迭代的东西(在Java中),以便我可以获取每个sender_id_t id值? 感谢任何建议。

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

Cfunction:

 //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': 

对此最简单的解决方案不涉及编写任何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  %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()文件重命名getFoo()并使其和相应的numFoo() private ,即实现细节。

使用这两个私有函数,我们可以编写一个真实的public Foo[] getFoo() ,调用这两个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之路。

为了完成“使其成为private ”方面,您可能还需要执行以下操作:

 %javamethodmodifiers foo_array_getitem "private"; %ignore foo_array_setitem; %ignore delete_foo_array; %ignore new_foo_array; %include  %array_functions(struct Foo, foo_array); 

隐藏由%array_functions宏生成的所有函数。