当前位置: 首页 > 知识库问答 >
问题:

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

籍英叡
2023-03-14

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

int err = new_instance(const char* name, instance_t* instance);

名称-输入,实例-输出

int err = get_value(const instance_t instance, int *val);

实例-输入,-输出

其中,实例定义为:

typedef void* instance_t;

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

// instance_t [argout]
%typemap(in, numinputs=0) instance_t* instance (instance_t temp = 0) {
    $1 = &temp;
}
%typemap(argout) instance_t *instance {
    %append_output(PyLong_FromLongLong((long long)* $1));
}
// instance_t [in]
%typemap(in) instance_t instance {
    $1 = (instance_t) PyLong_AsLongLong($input);
}

共有1个答案

马煌
2023-03-14

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

typedef void* instance_t;

int new_instance(const char* name, instance_t * instance);
int get_value(const instance_t instance, int *val);

我们可以使用cpointer。我从SWIG库中获取了一些函数,我们需要编写一个Java重载,调用默认版本的新实例(由于它成为一个实现细节,我们将其设置为私有)。

%module test

%{
#include "test.h"
%}

%include <cpointer.i>
// Have SWIG create a helper class for "pointer to pointer" type of handle
%pointer_class(instance_t, inst_ptr);
// Hide default version of new_instance
%javamethodmodifiers new_instance "private";

// Supply  Java version of new_instance now with useful method signature
%pragma(java) modulecode=%{
  public static SWIGTYPE_p_void new_instance(String name) {
    inst_ptr ptr = new inst_ptr();
    final int err = new_instance(name, ptr.cast());
    if (0!=err) {
      // throw or whatever
    }
    return ptr.value();
  }
%}

%include "test.h"

请注意,此示例可能会按原样泄漏,因为ptr.value()默认情况下是非拥有的。

在下一个示例中,我们仅在C中编写了一个“重载”(但由于我假设您编写的是C而不是C,因此我们必须使用%rename来使其工作),特别是针对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_p_void)会更加复杂。

%module test

%{
#include "test.h"
%}

// Provide 'instance' class for strong typing (instead of void* semantics)
%rename(Instance) instance;
%nodefaultctor;
struct instance {};
typedef instance * instance_t;

// Don't leak (not that we have a destructor yet, but...)
%newobject new_instance;

// Change new_instance to return instance of Instance

%typemap(jstype) int new_instance "$typemap(jstype,instance_t)";
%typemap(jni) int new_instance "$typemap(jni,instance_t)";
%typemap(jtype) int new_instance "$typemap(jtype,instance_t)";

// Hide the instance_t argument and use a temporary instead under the hood
%typemap(in,numinputs=0) instance_t * ($1_basetype tmp) %{
  $1 = &tmp;
%}
// After the call copy the result back
%typemap(argout) instance_t * %{
  *($1_ltype)&$result = *$1;
%}
// Inside Java construct the proxy with the correct long pointer
%typemap(javaout) int new_instance {
  return new $typemap(jstype,int new_instance)($jnicall, $owner);
}

// Some error handling
%javaexception("Exception") new_instance {
  $action
  if (!result) {
    // JNI code to raise exception, untested in this form
    jclass clazz = JCALL1(FindClass, jenv, "Exception");
    JCALL2(ThrowNew, jenv, clazz, "Failure creating thing");
    return $null;
  }
}

%include "test.h"

我鼓励您在调用new_instance()时查看生成的代码,以充分了解这些类型映射在做什么。

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

%include <typemaps.i>
%apply int *OUTPUT { int *val };

%include "test.h"

你会称之为:

int outarr[] = new int[1];
final int err = test.get_value(instance, outarr);
// outarr[0] then constains the value 

当然,你可以利用这个技巧,使用我在这个答案的第一个例子中的%pragma(java)modulecode来提供另一个行为更自然的重载:

%javamethodmodifiers get_value "private";

%pragma(java) modulecode=%{
  public static int get_value(Instance instance) {
    int outarr[] = new int[1];
    final int err = test.get_value(instance, outarr);
    if (0!=err) {
      // throw, blah blah
    }
    return outarr[0];
  }
%}

(请注意,这种使用数组的技巧也适用于实例_t*问题的第四种解决方案,但由于它不是一种原始类型,因此需要进行更多的工作,而没有真正的收益。)

 类似资料:
  • 我在目标语言为python的swig接口文件中成功地使用了以下类型映射: 然而,当我将目标语言更改为java时,当我尝试构建swg生成的自动生成的c包装代码时,我会遇到很多编译时错误,即。 等等... 我注意到,在python案例中,粘贴到swig包装器代码中的代码包含,等声明,这些代码来自 它位于 当目标语言为java时,此等效代码不会粘贴到swig包装器代码中。我不完全确定为什么不会发生这种情

  • 我使用SWIG类型映射包装一个类,使用SWIG提供的“std_vector.I”包装这个类的。目标语言是Python。除了我不能在向量上迭代之外,一切似乎都正常。 我创建了一个关于复数的最小示例(仅为方便起见,它与我的真实项目无关)。 这是我想包装的C类: 这是我的SWIG接口文件: 我可以使用以下Python代码简单地测试typecheck/in/out typemaps: 正如您在输出中看到的

  • 我在使用SWIG(3.0.6版)围绕C库生成Python包装时遇到了一些问题。 我的问题与应用输出类型映射有关,特别是在类类型的指针/引用的情况下。 为了说明,这就是我想要的标准类型,它是有效的: 您不必传入“resultLong”,但它会自动附加到结果中。太棒了 但是,当输出类型是指向类类型的指针时,这似乎不像我期望的那样工作: 问题似乎是SWIG没有以与简单类型相同的方式处理它。它仍然在包装函

  • 我将MySQL与Spring JDBC模板一起用于我的web应用程序。我需要只存储数字(10)的电话号码。我对使用数据类型的数据类型有点困惑。 MySQL中更可取的数据类型是什么

  • 问题 你想让你写的C代码作为一个C扩展模块来访问,想通过使用 Swig包装生成器 来完成。 解决方案 Swig通过解析C头文件并自动创建扩展代码来操作。 要使用它,你先要有一个C头文件。例如,我们示例的头文件如下: /* sample.h */ #include <math.h> extern int gcd(int, int); extern int in_mandel(double x0,

  • 问题内容: 我正在尝试使用SWIG为python包装一个C ++库。该库通过将 某些类型的回调函数 传递给类方法来频繁使用回调函数。 现在,在包装代码之后,我想从python创建回调逻辑。这可能吗?这是我正在尝试发现的实验..目前不起作用。 头文件和swig文件如下: paska.h: paska.i: 最后,我在python中测试.. 最后一行抛出“ TypeError:方法’handleri_