对C结构使用自定义创建者和删除者

时间:2015-05-27 08:44:41

标签: java c swig

我在C方面

typedef struct {} C_String;
C_String* StringNew();
void StringFree(C_String* string);

在Java上我得到了这样的包装类

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

  protected String(long cPtr, boolean cMemoryOwn) {
    swigCMemOwn = cMemoryOwn;
    swigCPtr = cPtr;
  }

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

  protected void finalize() {
    delete();
  }

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

  public String() {
    this(JNI.new_C_String(), true);
  }

}

JNI.new_С_String和JNI.delete_С_String是SWIG生成的本机方法,它们执行简单的工作 - 按C_String分配malloc并分别按free删除它。在我的情况下,情况应该是不同的,因为C_String是空结构并且行为类似于快捷方式,应该由StringNew分配,mallocStringFree引导并由JNI.new_String释放。

我想使用正确的方法代替JNI.delete_String"SELECT " + "CASE WHEN smth.status != 'BATMAN' THEN ... " + "ELSE (SELECT ... FROM ... WHERE ... ORDER BY ... DESC limit 1) " + "END, " + "next_field, " + "CASE WHEN smth.status == 'BATMAN' THEN ... " + "ELSE ... " + "END, " + "final_field_which_doesent_have_a_case_logic" + "FROM ... the_rest_of_the_normal_query"; 最简单的方法是什么?

1 个答案:

答案 0 :(得分:2)

假设您显示的C位于名为test.h的文件中,以下SWIG界面将执行您想要的操作:

%module test

%{
#include "test.h"
%}

%extend C_String {
  C_String() {
    return StringNew();
  }
  ~C_String() {
    StringFree($self);
  }
}

%ignore StringNew;
%ignore StringFree;

%include "test.h"

这使用%extendC_String类型提供自定义构造函数和析构函数。此构造函数/析构函数对分别只调用C函数StringNewStringFree

在您的问题中,您要求在生成的Java代码中进行这些调用。我上面写的方式使这些调用发生在C语言中。这有两个主要好处:

  1. 语言中立 - 无论您使用何种语言定位,相同的界面文件都能同样有效。
  2. 它最大限度地减少了本机和Java(或任何其他目标)代码之间的调用。从性能角度来看,这通常是件好事,因为这些跨语言跳转往往是界面中最昂贵的部分。
  3. 这个答案的其余部分主要是作为一个学习点,而不是推荐的解决方案。

    如果你真的想要,你可以把它写成Java,然后进行你要求的JNI电话。要做到这一点,你需要写一些typemaps,你至少需要两个(未经测试的)看起来像这样的东西:

    1. javabody:

      %typemap(javabody) C_String %{
        private long swigCPtr;
        protected boolean swigCMemOwn;
      
        protected $javaclassname(long cPtr, boolean cMemoryOwn) {
          swigCMemOwn = cMemoryOwn;
          swigCPtr = cPtr;
        }
      
        public $javaclassname() {
            $javaclassname tmp = $imclassname.StringNew();
            swigCMemOwn = tmp.swigCMemoryOwn;
            swigCPtr = tmp.swigCPtr;
            tmp.swigCMemoryOwn = false;
        }
      
        protected static long getCPtr($javaclassname obj) {
          return (obj == null) ? 0 : obj.swigCPtr;
        }
      %}
      
    2. javadestruct:

      %typemap(javabody) C_String %{
      public synchronized void delete() {
          if (swigCPtr != 0) {
            if (swigCMemOwn) {
              swigCMemOwn = false;
              $imclassname.StringFree(swigCPtr);
            }
            swigCPtr = 0;
          }
        }
      %}
      
    3. 但如前所述,这确实不是解决问题的最佳方法。 (如果您希望在继承的情况下仍然如此,那么您还需要' javadestruct_derived' typemap)