Use SWIG to Handle C Function Returning A Pointer to Array of Structure in Java

后端 未结 1 916
猫巷女王i
猫巷女王i 2021-01-25 12:48

I\'m trying to figure out what SWIG Interface file change is needed in order to handle the getFoo returns a pointer that points to an array of a custom structure (sender_id_t).

相关标签:
1条回答
  • 2021-01-25 13:30

    The simplest solution to this doesn't involve writing any JNI at all - in effect it's method 2. So what I did was use carrays.i to expose a very basic interface and then written a small bit of Java to make the public view of it more usable/intuitive. The key thing is you need to supply a way of bringing together the knowledge of the array and the length of it. I've put together a minimal complete example to illustrate, it returns a Java array, but it could equally work for an ArrayList or any collection you like.

    Firstly a header file, with an inline implementation for compactness:

    #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
    

    This is then wrapped with:

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

    Where we make rename the getFoo() from the header file and make it and the corresponding numFoo() private, i.e. implementation details.

    Using these two private functions we can then write a real, public Foo[] getFoo(), that calls these two and then copies the results into an actual array of known size.

    I tested this with:

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

    In my view this solution is cleaner than the corresponding JNI based example - it's simpler to write and harder to introduce bugs which makes it more maintainable. Any Java or C programmer that looks at it can pretty much see what's going on. It's probably not much worse in terms of performance and probably not going to be a big chunk of time on some critical path - if benchmarks show it to be a problem then it's still easy to go down the JNI road later.

    For completeness on the "making it private" aspect you might also want to do something like:

    %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);
    

    To hide all of the functions which get generated by the %array_functions macro.

    0 讨论(0)
提交回复
热议问题