java - 使用 C 结构的自定义创建器和删除器

标签 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 生成的 native 方法,它们执行简单的工作 - 分配 C_String通过malloc并通过 free 删除它分别。就我而言,场景应该有所不同,因为 C_String是空结构,就像快捷方式一样,正确的方法应该通过 StringNew 进行分配其中有malloc在引擎盖下并释放 StringFree .

我想使用正确的方法而不是 JNI.new_String , JNI.delete_String实现这一目标最简单的方法是什么?

最佳答案

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

%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. 它最大限度地减少了 native 代码和 Java(或任何其他目标)代码之间的调用。从性能角度来看,这通常是一件好事,因为这些跨语言跳转往往是界面中最昂贵的部分。

这个答案的其余部分主要只是作为学习点,而不是推荐的解决方案。

如果您确实愿意,您可以将其编写为 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;
        }
      }
    %}
    

但如前所述,这确实不是解决问题的最佳方法。 (如果您希望在继承的情况下仍然发生这种情况,您还需要一个“javadestruct_衍生”类型映射)

关于java - 使用 C 结构的自定义创建器和删除器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30477383/

相关文章:

python - Swig Python 不包装方法

Java null.equals(对象 o)

c - 如何将一个项目链接到同一个 C 静态库的两个不同版本?

c - 两个文件描述符都关闭后,Linux 会自动释放未命名的管道吗?

c - 卡在 sigwait 上

c++ - 如何在 C++ 中将用户数据从一个 Lua block 传递到另一个

c - 我应该为 ruby​​ Fixnum -> matlab mwSize 使用 SWIG 类型映射吗?

java - Log 4j根据模块写入不同文件的好方法

java - Android:如何使用加速度计计算设备掉落的高度?

java - Spark 无法从 webjar 加载静态文件