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

Pre*_*mal 5 c++ java swig

我有样本.h文件,如下所示:

class Test
{
public:
       void SelectValues(long long values[])
};
Run Code Online (Sandbox Code Playgroud)

我使用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"
Run Code Online (Sandbox Code Playgroud)

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

public void SelectValues(SWIGTYPE_p_long_long includeKeys)
Run Code Online (Sandbox Code Playgroud)

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

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

我已经阅读了这个问题,但它没有帮助我看到如何将数组从Java传递给C++.

Fle*_*exo 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);
Run Code Online (Sandbox Code Playgroud)

其中数组只是“真实”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());
Run Code Online (Sandbox Code Playgroud)

如果您愿意,实际上可以使用一些类型映射让 SWIG 做更多的事情。您的示例类不接受长度,SelectValues因此我假设您以 0 终止数组,尽管您同样可以通过一些简单的更改来传递长度。

(为了方便起见,我%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";
    }
  }
};
%}
Run Code Online (Sandbox Code Playgroud)

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

然后,我们需要一个in类型映射来安排从 jlong​​Array 到 C++ 端的转换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);
  }
}
Run Code Online (Sandbox Code Playgroud)

这完全符合你的希望。