2012-06-08 71 views
5

我有樣品h文件象下面這樣:如何通過陣列(在Java的長陣列)從Java到C++使用痛飲

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++。

+0

您在JNI方面看到的'jlong​​'是SWIG如何包裝所有不是原始類型的東西。 – Flexo

回答

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

實際上,你可以做,如果你想痛飲做的比這更多的與幾個typemaps。你的示例類沒有在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 typemap只是一個直通過程。在JNI的C++端,這是我們在另一個typemap中指定的jlongArray

然後,我們需要一個in類型表安排在C++側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); 
    } 
} 

這的確完全按照你的希望。

+0

如果你不想使用0來終止數組,你需要將SelectValues更改爲:'void SelectValues(long long values [],size_t len);' - 如果你願意,我可以將它添加到我的答案中想。 – Flexo

+0

我在最後添加了該示例:http://stackoverflow.com/q/11584599/168175 – Flexo