我在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"
这使用 %extend
为 C_String
类型提供自定义构造函数和析构函数。该构造函数/析构函数对仅分别调用 C 函数 StringNew
和 StringFree
。
在您的问题中,您要求从生成的 Java 代码中进行这些调用。我上面编写的方式使这些调用在 C 内部发生。这有两个主要好处:
- 它是语言中立的 - 无论您的目标语言是什么,相同的界面文件都同样有效。
- 它最大限度地减少了 native 代码和 Java(或任何其他目标)代码之间的调用。从性能角度来看,这通常是一件好事,因为这些跨语言跳转往往是界面中最昂贵的部分。
这个答案的其余部分主要只是作为学习点,而不是推荐的解决方案。
如果您确实愿意,您可以将其编写为 Java 并进行您要求的 JNI 调用。为此,您需要编写一些 typemaps ,您至少需要两个(未经测试的)可能类似于:
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; } %}
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/