2013-07-09 90 views
4

我試圖來包裝與Java下面的C++函數:使用痛飲轉換C++的char *爲char []在Java中,而不是字符串

char* MyClass::to_cstring(); 

此函數的輸出返回Java String對象。我希望它作爲char[] Java數組返回。我目前使用「typemaps.i」和「std_string.i」。有沒有一種方法可以覆蓋這樣的行爲,即std :: string仍然作爲Java String返回,但char*作爲Java char數組返回?

如何使用Java byte[]而不是char[],因此不需要擔心在8位C++字符和Java的16位Unicode之間進行轉換?

+0

至少,這必須是Java中的byte []'。 Java的'char'是一個UTF-16編碼單元。 –

+0

謝謝。我更新了這個問題。 – dcdo

回答

2

要做到這一點,你需要用你自己的默認SWIG提供的默認類型。要做到這一點最簡單的方法只需要編寫一些Java的「膠水」:

%module test 

%typemap(jstype) char *to_cstring() "byte[]"; 
%typemap(javaout) char *to_cstring() { 
    return $jnicall.getBytes(); 
} 

%inline %{ 
char *to_cstring() { 
    static char ret[] = "hello world"; 
    return ret; 
} 
%} 

不正是你想要的東西通過調用getBytes()在默認幕後返回String

你也可以做到這一點有一些自己的JNI它通過從您的本機代碼返回一個字節數組一路:

%module test 

%typemap(jstype) char *to_cstring() "byte[]"; 
%typemap(jtype) char *to_cstring() "byte[]"; 
%typemap(javaout) char *to_cstring() { 
    return $jnicall; 
} 
%typemap(jni) char *to_cstring() "jbyteArray"; 
%typemap(out) char *to_cstring() { 
    const size_t len = strlen($1); 
    $result = JCALL1(NewByteArray, jenv, len); 
    // TODO: check that this succeeded 
    JCALL4(SetByteArrayRegion, jenv, $result, 0, len, (const jbyte*)$1); 
} 

%inline %{ 
char *to_cstring() { 
    static char ret[] = "hello world"; 
    return ret; 
} 
%} 

這裏的區別在於,映射到byte[]發生在生成的JNI,而不是在Java膠水中。現在,粘合劑只是直接代理JNI。

我可以用下面的Java測試和驗證這些typemaps:

public class run { 
    public static void main(String[] argv) { 
    System.loadLibrary("test"); 
    byte[] ret = test.to_cstring(); 
    System.out.println(ret.length); 
    System.out.println((char)ret[0]); 
    } 
} 

在這兩個例子雙方的返回類型(char *)和函數to_cstring()的typemaps比賽。您可以調整此類型圖匹配以選擇性更強或更弱。它目前不會改變最常用的用法,您也可以使用%apply將typemap複製到其他不完全匹配的情況。