How to use SWIG Generated C structures in Java as

2020-07-20 19:13发布

问题:

I have a SWIG interface file that exposes some C functions (via JNI) to my Java application and these C structures are used as input into the C function (via SWIG/JNI). SWIG generates the structure as a Java class, but I'm unsure how to set the structures properties as the setters take a SWIG generated type. I need to set the structures properties before passing it as input into the C function from my Java class. example_location_id_t_ is the class I need to pass, but the setters for Id and Phy_idx take the below SWIG types. How do I populate the SWIGTYPE_p_unsigned_char and SWIGTYPE_p_uint32_t so that I can set the Id and Phy_idx properties of the SWIGTYPE_p_uint32_t class?

setId(SWIGTYPE_p_unsigned_char value) and setPhy_idx(SWIGTYPE_p_uint32_t value)

package com.test.jni;

public class SWIGTYPE_p_unsigned_char {
  private long swigCPtr;

  protected SWIGTYPE_p_unsigned_char(long cPtr, boolean futureUse) {
    swigCPtr = cPtr;
  }

  protected SWIGTYPE_p_unsigned_char() {
    swigCPtr = 0;
  }

  protected static long getCPtr(SWIGTYPE_p_unsigned_char obj) {
    return (obj == null) ? 0 : obj.swigCPtr;
  }
}


package com.test.jni;

public class SWIGTYPE_p_uint32_t {
  private long swigCPtr;

  protected SWIGTYPE_p_uint32_t(long cPtr, boolean futureUse) {
    swigCPtr = cPtr;
  }

  protected SWIGTYPE_p_uint32_t() {
    swigCPtr = 0;
  }

  protected static long getCPtr(SWIGTYPE_p_uint32_t obj) {
    return (obj == null) ? 0 : obj.swigCPtr;
  }
}

package com.test.jni;

public class example_location_id_t_ {
  private long swigCPtr;
  protected boolean swigCMemOwn;

  public example_location_id_t_ (long cPtr, boolean cMemoryOwn) {
    swigCMemOwn = cMemoryOwn;
    swigCPtr = cPtr;
  }

  public static long getCPtr(example_location_id_t_ obj) {
    return (obj == null) ? 0 : obj.swigCPtr;
  }

  protected void finalize() {
    delete();
  }

  public synchronized void delete() {
    if (swigCPtr != 0) {
      if (swigCMemOwn) {
        swigCMemOwn = false;
        ExampleJNI.delete_example_location_id_t_(swigCPtr);
      }
      swigCPtr = 0;
    }
  }

  public void setId(SWIGTYPE_p_unsigned_char value) {
      ExampleJNI.example_location_id_t__id_set(swigCPtr, this, SWIGTYPE_p_unsigned_char.getCPtr(value));
  }

  public SWIGTYPE_p_unsigned_char getId() {
    long cPtr = ExampleJNI.example_location_id_t__id_get(swigCPtr, this);
    return (cPtr == 0) ? null : new SWIGTYPE_p_unsigned_char(cPtr, false);
  }

  public void setPhy_idx(SWIGTYPE_p_uint32_t value) {
    ExampleJNI.example_location_id_t__phy_idx_set(swigCPtr, this, SWIGTYPE_p_uint32_t.getCPtr(value));
  }

  public SWIGTYPE_p_uint32_t getPhy_idx() {
    return new SWIGTYPE_p_uint32_t(ExampleJNI.example_location_id_t__phy_idx_get(swigCPtr, this), true);
  }

  public example_location_id_t_() {
    this(ExampleJNI.new_example_location_id_t_(), true);
  }

}

回答1:

Without being given any extra information SWIG defaults to assuming you want things wrapped as a type that can be returned and passed from one function to another, even if it can't be wrapped meaningfully in the target language.

Every time you see a type that begins SWIGTYPE_... it means SWIG didn't know how to generate a better wrapper and this was the best it managed to come up with.

SWIG does provide default typemaps that can help you here though:

  • For setPhy_idx(uint32_t value); all you need to add in your interface is:

    %include "stdint.i"
    
    void setPhy_idx(uint32_t value);
    

    and a type which can represent a uint32_t will be used in the target language.

  • For setId(unsigned char *value); it depends quite what value actually is - if it's a NULL terminated string you can do something like:

    %apply char * { unsigned char * };
    
    void setId(unsigned char *value);
    

    and a String will be used in your target language.

    If you wanted to pass the pointer as an integer type you could use something like:

    %apply unsigned long { unsigned char * };
    
    void setId(unsigned char *value);
    

    instead.

    If unsigned char *value is a pointer to a single unsigned char you could do:

    %include "typemaps.i"
    %apply unsigned char *INPUT { unsigned char *value };
    
    void setId(unsigned char *value);
    

    which instructs SWIG to treat the poitner as a single pointer. (This could be applied for the uint32_t if it was a pointer too)