如何使用Swig将数组(java中的long数组)从Java传递给C ++

时间:2012-06-08 10:59:50

标签: java c++ swig

我的样本.h文件如下:

class Test
{
public:
       void SelectValues(long long values[])
};

我使用SWIG并从.i文件下面创建了JNI接口

%module MyLib
%include "carrays.i"
%array_functions(long long, long_long_array )


%{
  #include "Test.h"
%}

/* Let's just grab the original header file here */
%include <windows.i> /*This line is used for calling conventions*/ 
% include "Test.h"

当我创建Java方法时,它创建如下:

public void SelectValues(SWIGTYPE_p_long_long includeKeys)

同样对于JNI文件,它将参数作为jlongArray,但仅采用简单的jlong。由于这个问题,我无法创建像long[]={1L,2L}这样的长数组,并将其传递给Java方法以上,以调用适当的JNI方法。

我希望SWIG以这样的方式生成接口,我可以将上面提到的数组传递给我的C ++方法。

我已阅读this question,但它无法帮助我了解如何将数组从Java传递到C ++。

1 个答案:

答案 0 :(得分:2)

你在这里使用array_functions所做的是正确和可用的,但它专注于直接包装C ++代码,并且它不会使用底层Java数组。您可以使用以下内容:

SWIGTYPE_p_long_long array = MyLib.new_long_long_array(100); // new array with 100 elements.
for (int i = 0; i < 100; ++i) {
  long_long_array_setitem(array, i, i);
}
new Test().SelectValues(array);

其中array只是一个“真正的”C ++内存块的代理,您可以在Java端读取/写入并传递给包装函数。

我猜你的问题是你有兴趣让这种感觉在Java方面更“自然”。 SWIG还提供array_class,它类似地包装数组,但是作为一个适当的对象而不是静态函数的集合。例如,如果您将接口文件更改为使用array_class(long long, LongLongArray)而不是array_functions,则可以执行以下操作:

LongLongArray array = new LongLongArray(100);
for (int i = 0; i < 100; ++i) {
   array.setitem(i,i); 
}
new Test().SelectValues(array.cast());

如果您愿意,实际上您可以使SWIG做多于一些类型图的操作。你的示例类在SelectValues中的长度并不长,所以我假设你终止了数组,尽管你可以通过一些简单的改变来传递长度。

(为方便起见,我%inline你的班级减少了文件的数量,并添加了一个虚拟的文件实现用于测试)

%module MyLib

%{
#include <iostream>
%}

%typemap(jtype) long long values[] "long[]"
%typemap(jstype) long long values[] "long[]"
%typemap(javain) long long values[] "$javainput"
%typemap(jni) long long values[] "jlongArray"
%typemap(in) long long values[] {
  jboolean isCopy;
  $1 = JCALL2(GetLongArrayElements, jenv, $input, &isCopy);
}

%inline %{
class Test
{
public:
  void SelectValues(long long values[]) {
    while (*values) {
      std::cout << *values++ << "\n";
    }
  }
};
%}

这里我们说代理类SWIG都生成,它生成的JNI类将使用long[],即Java数组。我们不需要在Java代理到Java JNI转换中执行任何操作,因此javain类型映射只是直接传递。在JNI的C ++端是jlongArray,我们也在另一个typemap中指定了它。

然后我们需要一个in类型映射来安排从Clong端的jlong​​Array到long long[]的转换 - 对此有一个JNI调用,我们不关心它是副本还是实际的内存来自我们最终使用的JVM。 (您可能会关心是否要修改结果并将其显示在Java内部)例如

我测试了这个:

public class run {
  public static void main(String[] argv) {
    System.loadLibrary("mylib");
    long arr[] = {100,99,1,0}; // Terminate with 0!
    new Test().SelectValues(arr);
  }
}

完全按照你的意愿行事。