Java 使用SWIG的C函数JNI包装器-类型映射应该是什么?

Java 使用SWIG的C函数JNI包装器-类型映射应该是什么?,java,c,java-native-interface,swig,Java,C,Java Native Interface,Swig,我正在尝试为C中的以下函数创建JNI包装器: int err = new_instance(const char* name, instance_t* instance); 名称-输入,实例-输出 int err = get_value(const instance_t instance, int *val); 实例-输入,val-输出 int err = get_value(const instance_t instance, int *val); 其中,实例定义为: typedef v

我正在尝试为C中的以下函数创建JNI包装器:

int err = new_instance(const char* name, instance_t* instance);
名称
-输入,
实例
-输出

int err = get_value(const instance_t instance, int *val);
实例
-输入,
val
-输出

int err = get_value(const instance_t instance, int *val);
其中,
实例
定义为:

typedef void* instance_t;
我完全沉浸在Java的SWIG手册中,因为它不简单地支持输入参数作为输出类型。我对Python包装器没有任何问题(如下所示)

在Java中使用typemap的正确方法是什么?
您可以通过几种不同的方式使用SWIG和Java来实现这一点。根据您在问题中所展示的内容,我创建了以下标题来说明我的所有示例:

typedef void* instance_t;

int new_instance(const char* name, instance_t * instance);
int get_value(const instance_t instance, int *val);
在接口中编写一些Java: 我们可以使用SWIG库中的函数为我们提供编写Java重载所需的函数,该重载调用默认版本的
new\u instance
(我们将其设置为私有,因为它成为了一个实现细节)

%模块测试
%{
#包括“test.h”
%}
%包括
//让SWIG为“指针指向指针”类型的句柄创建一个帮助器类
%指针类(实例、仪器ptr);
//隐藏新实例的默认版本
%javamethodmodifiers新的_实例“private”;
//现在提供Java版本的新_实例,并提供有用的方法签名
%pragma(java)模块代码=%{
公共静态SWIGTYPE_p_void new_实例(字符串名称){
inst_ptr ptr=新inst_ptr();
final int err=new_实例(名称ptr.cast());
如果(0!=错误){
//扔什么
}
返回ptr.value();
}
%}
%包括“test.h”
请注意,此示例可能会按原样泄漏,因为默认情况下,
ptr.value()
为非所有者

在接口中编写一些C:

在下面的例子中,我们写了一个“重载”(但是,既然我假设你在写C而不是C++),我们必须单独使用C代码> %ReNeXe//Cube来实现这一工作,特别是针对SWIG接口。函数的原始版本被完全忽略,因为它对我们来说非常无用

%module test

%{
#include "test.h"
%}

// Hide the default new_instance
%ignore new_instance;
%include "test.h"
// Pretend our wrapper specific "overload" was called new_instance all along
%rename(new_instance) new_instance_overload;
// Don't leak our new instance
%newobject new_instance;

// Declare, define and wrap a special version of new_instance
%inline %{
    instance_t new_instance_overload(const char* name) {
        instance_t result = NULL;
        const int err = new_instance(name, &result);
        if (err) {
            // See later on/other Q for cross language exception example
        }
        return result;
    }
%}
使用打字图 实际上,我们可以使用Java类型映射来做一些与Python示例非常类似的事情,尽管这个过程更加复杂,因为Java具有强大的类型,我们需要尊重这一点

这个解决方案也基本上类似于相同的基础问题,当基础typedef是
void*
而不是结构的前向声明时,在Java中使用强类型(而不仅仅是
SWIGTYPE\u p\u void
)更为复杂

%模块测试
%{
#包括“test.h”
%}
//为强类型提供“实例”类(而不是void*语义)
%重命名(实例)实例;
%nodefaultor;
结构实例{};
typedef实例*instance_t;
//不要泄漏(不是说我们有一个析构函数,但是…)
%新对象新实例;
//将新的_实例更改为返回实例的实例
%typemap(jstype)int new_实例“$typemap(jstype,instance_t)”;
%typemap(jni)int new_实例“$typemap(jni,instance_t)”;
%typemap(jtype)int new_实例“$typemap(jtype,instance_t)”;
//隐藏instance_t参数,并在引擎盖下使用临时参数
%typemap(in,numinputs=0)实例\u t*($1\u basetype tmp)%{
$1=&tmp;
%}
//呼叫结束后,将结果复制回来
%类型映射(argout)实例*{
*($1_ltype)和$result=*$1;
%}
//在Java内部,使用正确的长指针构造代理
%typemap(javaout)int new_实例{
返回新的$typemap(jstype,int new_实例)($jnicall,$owner);
}
//一些错误处理
%javaexception(“Exception”)新的\u实例{
$action
如果(!结果){
//用于引发异常的JNI代码,未在此表单中测试
jclass clazz=JCALL1(FindClass,jenv,“异常”);
JCALL2(ThrowNew,jenv,clazz,“失败创造的东西”);
返回$null;
}
}
%包括“test.h”
我鼓励您在调用
new\u instance()
时查看生成的代码,以充分了解这些类型映射在做什么

就调用
get\u value
而言,
instance\u t
会从上面的接口自动处理,
int*
arg out需要像上面的例子一样处理,或者使用一个只包含一个元素的数组的技巧:

%include
%应用int*输出{int*val};
%包括“test.h”
您可以将其称为:

int outarr[]=新的int[1];
final int err=test.get_值(实例,outarr);
//outarr[0]则保持该值
当然,您可以使用这个技巧,使用类似于我在这个答案中的第一个示例的
%pragma(java)modulecode
的东西来提供另一个行为更自然的重载:

%javamethodmodifiers获取值“private”;
%pragma(java)模块代码=%{
公共静态int get_值(实例){
int outarr[]=新int[1];
final int err=test.get_值(实例,outarr);
如果(0!=错误){
//扔,废话
}
返回输出[0];
}
%}

(请注意,使用数组的这个技巧也可以解决
实例*
问题的第四个解决方案,但因为它不是一个原始类型,所以需要做更多的工作才能获得真正的收益)

您认为Java对
void*
有什么意义?您可以将指针保持尽可能长的时间,但据我所知,这不会遵循SWIG原理。我想,由于Java没有指针的概念,它会将
实例\u t*
句柄视为一个长的数字-这不是真的吗?您需要做出一个简洁的决定,在Java中应该是什么类型。
instance\u t
是不透明的句柄吗?或者某种类型的接口?Java不需要知道关于
instance\t
类型的任何信息,只需要将其视为指针值。不需要特殊的接口。我认为Python的例子说明了这一点,我确实意识到Java不支持将输入参数作为返回类型(