问题描述
我有如下的样例.h文件:
class Test
{
public:
void SelectValues(long long values [])
};
我使用SWIG并从下面创建JNI接口.i文件
%module MyLib
%includecarrays.i
%array_functions(long long,long_long_array)
b $ b%{
#includeTest.h
%}
/ *让我们在这里抓住原始的头文件* /
%include< windows.i> / *此行用于调用约定* /
%includeTest.h
当创建Java方法时,它创建如下:
public void SelectValues(SWIGTYPE_p_long_long includeKeys)
此外,对于JNI文件,它以 jlongArray
c> jlong 。由于这个问题,我不能创建long像 long [] = {1L,2L}
的数组,并将其传递给Java方法调用适当的JNI方法。
我希望SWIG以这样一种方式生成接口,我可以将上述数组传递给我的C ++方法。
请阅读,但它没有帮助我看看如何将一个数组从Java传递给C ++。
c $ 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 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 array.setitem(i,i);
}
new Test()。SelectValues(array.cast());
如果你愿意,你可以使SWIG比一些类型的电子书做得更多。你的示例类在 SelectValues
中不占用长度,所以我假设你是0终止数组,虽然你可以同样好地传递长度与几个简单的更改。
(为了方便起见,我%inline
d减少文件数量并添加一个虚拟实现它用于测试)
%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 $ b jboolean isCopy;
$ 1 = JCALL2(GetLongArrayElements,jenv,$ input,& isCopy);
}
%inline%{
class Test
{
public:
void SelectValues(long long values []){
while(* values){
std :: cout<< *值++<< \\\
;
}
}
};
%}
在这里,我们说代理类SWIG生成和JNI类生成将使用 long []
,即Java数组。我们不需要在Java代理到Java JNI转换中做任何事情,因此 javain
typemap只是直接传递。在JNI的C ++一侧,它是一个 jlongArray
,我们也在另一个typemap中指定。
然后我们需要在
typemap中安排从jlongArray转换为 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);
}
}
p>
I have sample .h file like below:
class Test
{
public:
void SelectValues(long long values[])
};
I used SWIG and created JNI interface from below .i file
%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"
When I create Java method it creates like:
public void SelectValues(SWIGTYPE_p_long_long includeKeys)
Also for JNI file it is taking argument as jlongArray
but taking simple jlong
only. Due to this issue I cannot create array of long like long[]={1L,2L}
and pass it to above Java method to call appropriate JNI method.
I want SWIG to generate interface in such a way that I can pass above mentioned array to my C++ method.
I have read this question, but it didn't help me see how to pass an array from Java to C++.
What you've done here with array_functions
is correct and usable, but it's focused on wrapping the C++ code directly, and it won't be using an underlying Java array. You can use it with something like:
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);
where array is just a proxy to a "real" C++ chunk of memory that you can read/write from on the Java side and pass to wrapped functions.
I'm guessing from your question that you're interested in making this feel more "natural" on the Java side. SWIG also provides array_class
which wraps an array similarly, but as a proper object rather than a collection of static functions. For example if you changed your interface file to use array_class(long long, LongLongArray)
instead of array_functions
you can do:
LongLongArray array = new LongLongArray(100);
for (int i = 0; i < 100; ++i) {
array.setitem(i,i);
}
new Test().SelectValues(array.cast());
You can actually make SWIG do more than that with a few typemaps if you want to. Your example class doesn't take a length in SelectValues
so I'm assuming you're 0 terminating the array although you can equally well pass the length in with a few simple changes.
(For convenience I %inline
d your class to reduce the number of files and added a dummy implementation of it for testing)
%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";
}
}
};
%}
Here we said that both the proxy class SWIG generates and the JNI class it generates are going to be working with long[]
, i.e. a Java array. We don't need to do anything in the Java Proxy to Java JNI conversion, so the javain
typemap is just a straight pass through. On the C++ side of the JNI that's a jlongArray
, which we also specified in another typemap.
We then need an in
typemap to arrange converting from jlongArray to long long[]
in the C++ side - there's a single JNI call for that and we don't care if it's a copy or the actual memory from the JVM that we end up using. (You might care if you wanted to modify the results and make it visible back inside Java for example)
I tested this with:
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);
}
}
Which did exactly as you'd hope.
这篇关于如何使用Swig将数组(java中的long数组)从Java传递到C ++的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!