java - Swig 类型映射将变量地址作为参数传递?

标签 java c++ swig

我为以下 C++ 代码创建了 JNI 包装器。

add.h

class MyClass
    {
    public:   
        int add(int x, int y, int &z); 
        int sub(int x, int y);
    };

上面提到的代码就是.h文件

添加.cpp

int MyClass::add(int x, int y, int &sum)
{
    sum=x+y;
    return 0;
}

int MyClass::sub(int x, int y)
{
        return x - y;
}

swig.i

%module algo

%{
    #define SWIG_FILE_WITH_INIT
    #include "add.h"
%}
%include "arrays_java.i"
%include "typemaps.i"

%include "add.h"

对于上面提到的 .cpp 文件,我需要生成 JNI 包装器并将其用于 Java 代码。当我尝试执行 swig 命令时,我得到了 SWIGTYPE_p_int.java 文件和 JNI 文件。谁能帮我解决这个问题?

最佳答案

要包装 C++“通过非常量引用返回”函数,有很多选项可供选择。简而言之,您可以执行以下操作之一:

  1. 使用 %extend 提供一个返回的重载。 (可选择隐藏原件)
  2. 使用类型映射将其转换为返回值(并可选择将其映射到
  3. 更多地使用 SWIGTYPE_p_int。 (可选择在 Java 内部构建重载)
  4. 使用现有的 SWIG OUTPUT 类型映射通过数组获得按引用语义传递
  5. 使用结构体来获得按引用传递的语义

我将在此处展示每个选项的示例。


1。使用 %extend 提供重载

这里的基本思想是,我们将在此处编写一个全新的重载,SWIG 对其进行简单包装。使用下面的 %extend 语法,我们可以创建一个新的、仅包装器的重载,它使用临时存储值,然后在一切顺利时返回它。

%module algo

%{
    #define SWIG_FILE_WITH_INIT
    #include "add.h"
    #include <exception>
%}

%extend MyClass {
    int add(int x, int y) {
        int z;
        const int result = $self->add(x,y,z);
        if (0 == result) return z;
        throw std::exception();
        // TODO: use SWIG's exception support
    }
}

%ignore MyClass::add(int,int,int&); // Optional: hide the original overload
%include "add.h"

由于原始返回的 int 似乎指示函数本身的成功/失败,我们可以更自然地将其映射到 Java 中的异常。 (此处略去,详见我在XXX的回答)

2。使用类型映射返回它

这个解决方案的效果和上一个类似,只是实现方式不同。在这里,我们使用带有 numinputs=0in 类型映射来设置一个我们可以在调用发生时使用的临时变量 (tmpz) .然后 out 类型映射只检查来自真实函数调用的返回代码,argout 类型映射将 tempoary 复制到结果中。我在这里包含了比实际需要更多的类型映射,因为碰巧 z 和现有函数返回的类型相同,但如果不是这种情况,我们将需要它们。

%module algo

%{
    #define SWIG_FILE_WITH_INIT
    #include "add.h"
    #include <exception>
%}

// These aren't actually needed here because the fuction already returns in
%typemap(jni) int MyClass::add "jint";
%typemap(jtype) int MyClass::add "int";
%typemap(jstype) int MyClass::add "int";
%typemap(javaout) int MyClass::add {
  return $jnicall;
}

// These create a temporary and map it to the return value for us
%typemap(argout) int& z {
  $result = (jint)tmpz$argnum;
}
%typemap(out) int MyClass::add {
  if ($1 != 0) {
     throw std::exception();
     // TODO: exceptions as in other examples
  }
}
%typemap(in,numinputs=0) int& z (int tmpz) {
  $1 = &tmpz;
}
%include "add.h"

3。使用 SWIG 指针函数

在这里,我们将使用 SWIG 的 cpointer.i 库来帮助我们处理 SWIGTYPE_p_int 对象,并为我们的 Java 用户透明地执行此操作。为此,我们使用 javacode 类型映射为 z 创建了一个临时变量,然后将其传递给原始 SWIG 生成的函数(可以将其设为私有(private)以隐藏它)。与其他示例一样,我们可以通过抛出异常来处理返回值指示错误的情况,尽管这次已经是 Java 代码在执行抛出,这稍微简单一些。

%module algo

%{
    #define SWIG_FILE_WITH_INIT
    #include "add.h"
%}
%include "cpointer.i"
%pointer_class(int,IntPointer);
%typemap(javacode) MyClass %{
    public int add(int x, int y) {
        IntPointer z = new IntPointer();
        int ret = this.add(x,y,z.cast());
        if (ret != 0) throw new Exception();
        return z.value();
    }
%}
%javamethodmodifiers MyClass::add(int,int,int&) "private" // Optional
%include "add.h"

4。使用 OUTPUT 类型映射

这在功能上与之前的解决方案非常相似,不同的是我们使用数组而不是使用 SWIG 提供的辅助类型来处理 int 指针,并在底层利用 Java 的“按引用传递数组”语义来实现同样的结果。

%module algo

%{
    #define SWIG_FILE_WITH_INIT
    #include "add.h"
%}
%include <typemaps.i>
%apply int *OUTPUT { int & z };
%typemap(javacode) MyClass %{
    public int add(int x, int y) {
        int[] z = new int[1];
        int ret = this.add(x,y,z);
        if (ret != 0) throw new Exception();
        return z[0];
    }
%}
%javamethodmodifiers MyClass::add(int,int,int&) "private"
%include "add.h"

5.使用我们自己的结构进行引用传递

您可以使用 %inline 添加其他类型。然后欺骗 SWIG 使用它而不是 int& 引用。只要我们允许隐式转换就可以了。

%module algo

%{
    #define SWIG_FILE_WITH_INIT
    #include "add.h"
%}
%inline %{
    struct IntWrapper {
        int value;
        // Enable transparent conversion for the SWIG argument
        operator int&() {
          return value;
        }
    };
%}
class MyClass
    {
    public:   
        int add(int x, int y, IntWrapper& z); // lie to SWIG, but we'll make it up later with implict conversion
        int sub(int x, int y);
    };
//%include "add.h" // Don't do this now because we need the lie above

与前面的示例一样,我们可以选择通过重载和方法修饰符的使用对 Java 用户隐藏此实现细节。

有关以上几个示例中提出的异常点的更多信息,请参阅 here , 或 here .

关于java - Swig 类型映射将变量地址作为参数传递?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44568507/

相关文章:

java - Hibernate继承hql类型

c++ - float 的异常处理 C++

c++ - Swig + tcl + c++(内存管理)

java - Spring:bean 的映射,尝试在另一个 bean 中注入(inject)依赖项,获取空指针

java - 绘制两个重叠的图像

java - 如何在 eclipse 上右键单击 new->MyNewMenu 添加弹出菜单?

c++ - Visual C++ C4723 警告描述中的 "potential divide by zero"是什么意思?

python - Numpy 数组与 C++ vector 在内存效率方面的对比

python - Raspberry Pi CEC 代码的 SWIG 产生 undefined symbol 错误

python - SWIG Python包装,除法运算符重载很奇怪