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

标签 java c++ swig

我有如下示例 .h 文件:

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

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

%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 文件,它也将参数作为 jlong​​Array,但仅采用简单的 jlong​​。由于这个问题,我无法创建像 long[]={1L,2L} 这样的 long 数组并将其传递给上面的 Java 方法以调用适当的 JNI 方法。

我希望 SWIG 以我可以将上述数组传递给我的 C++ 方法的方式生成接口(interface)。

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

最佳答案

您在这里使用 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,它类似地包装了一个数组,但作为一个适当的对象而不是静态函数的集合。例如,如果您将接口(interface)文件更改为使用 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 代理到 Java JNI 的转换中做任何事情,所以 javain 类型映射只是一个直接的传递。在 JNI 的 C++ 端,它是一个 jlong​​Array,我们也在另一个类型映射中指定了它。

然后我们需要一个 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);
  }
}

这完全符合您的希望。

关于java - 如何使用 Swig 将数组(java 中的 long 数组)从 Java 传递到 C++,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10947560/

相关文章:

java - ClassNotFoundException org.openqa.selenium.WebDriver

c++ - 如何定义一个函数以将实例作为类中方法的参数并从测试文件中调用它?

python - 将我自己的 get/set C++ 成员函数视为 SWIG 中的成员变量?

c# - SWIG:生成 C# 包装器时 SWIGTYPE_p_void 未定义

java - Spring 将entitymanager getResultList结果转换为JSON

java - 多模块JHipster应用程序

java - HttpURLConnection:getResponseMessage()、getInputStream() 和 getContent() 之间的区别

c++ - "invalid argument"用于 av_buffersrc_write_frame/av_buffersrc_add_frame

C++ "' 形状' : cannot instantiate abstract class"can't find the source of the problem

python - 如何处理Python中被调用库生成的弹出错误提示?