5

我有如下示例 .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 like 数组long[]={1L,2L}并将其传递给上面的 Java 方法以调用适当的 JNI 方法。

我希望 SWIG 以这样一种方式生成接口,即我可以将上述数组传递给我的 C++ 方法。

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

4

1 回答 1

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);

其中数组只是“真实”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所以我假设您是 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";
    }
  }
};
%}

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

然后我们需要一个in类型映射来安排从 jlong​​Array 到long long[]C++ 端的转换 - 有一个 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);
  }
}

这完全符合您的期望。

于 2012-06-08T13:38:21.597 回答