swigのtypemapsと配列の使い方が少し失われています。私はswigを使ってjavaとcの間の配列を使用する実装例を用意しましたが、それが正しい方法かどうかはわかりません。SWIGを使って配列とやりとりする正しい方法
基本的に私は、バイト配列byte[]
をjavaからcのaigned char * `+サイズに渡したいと思っています。それをcで修正してjavaの変更を見て、cで配列を作成してJavaで使用します。 How can I make Swig correctly wrap a char* buffer that is modified in C as a Java Something-or-other?
、実際に は、例を作るためのガイドとしてのソリューションを使用し、 How to pass array(array of long in java) from Java to C++ using Swig、 Pass an array to a wrapped function as pointer+size or range:
私はtheeseの質問を見てみる必要があります。
これは、ファイルarrays.hで私のコードです:
#include <iostream>
bool createArray(signed char ** arrCA, int * lCA){
*lCA = 10;
*arrCA = (signed char*) calloc(*lCA, sizeof(signed char));
for(int i = 0; i < *lCA; i++){
(*arrCA)[i] = i;
}
return *arrCA != NULL;
}
bool readArray(const signed char arrRA[], const int lRA){
for(int i = 0; i < lRA; i++){
std::cout << ((unsigned int) arrRA[i]) << " ";
}
std::cout << std::endl;
return true;
}
bool modifyArrayValues(signed char arrMA[], const int lMA){
for(int i = 0; i < lMA; i++){
arrMA[i] = arrMA[i] * 2;
}
return true;
}
bool modifyArrayLength(signed char arrMALIn[], int lMALIn, signed char ** arrMALOut, int * lMALOut){
*lMALOut = 5;
*arrMALOut = (signed char*) calloc(*lMALOut, sizeof(signed char));
for(int i = 0; i < *lMALOut; i++){
(*arrMALOut)[i] = arrMALIn[i];
}
return true;
}
これはSWIGのため.iファイル(arrays.i)である:テストへ
%module arrays
%{
#include "arrays.h"
%}
%typemap(jtype) bool createArray "byte[]"
%typemap(jstype) bool createArray "byte[]"
%typemap(jni) bool createArray "jbyteArray"
%typemap(javaout) bool createArray { return $jnicall; }
%typemap(in, numinputs=0) signed char ** arrCA (signed char * temp) "$1=&temp;"
%typemap(in, numinputs=0) int * lCA (int l) "$1=&l;"
%typemap(argout) (signed char ** arrCA, int * lCA) {
$result = JCALL1(NewByteArray, jenv, *$2);
JCALL4(SetByteArrayRegion, jenv, $result, 0, *$2, (const jbyte*) *$1);
}
%typemap(out) bool createArray {
if (!$1) {
return NULL;
}
}
%typemap(jtype) (const signed char arrRA[], const int lRA) "byte[]"
%typemap(jstype) (const signed char arrRA[], const int lRA) "byte[]"
%typemap(jni) (const signed char arrRA[], const int lRA) "jbyteArray"
%typemap(javain) (const signed char arrRA[], const int lRA) "$javainput"
%typemap(in,numinputs=1) (const signed char arrRA[], const int lRA) {
$1 = JCALL2(GetByteArrayElements, jenv, $input, NULL);
$2 = JCALL1(GetArrayLength, jenv, $input);
}
%typemap(freearg) (const signed char arrRA[], const int lRA) {
// Or use 0 instead of ABORT to keep changes if it was a copy
JCALL3(ReleaseByteArrayElements, jenv, $input, $1, JNI_ABORT);
}
%typemap(jtype) (signed char arrMA[], const int lMA) "byte[]"
%typemap(jstype) (signed char arrMA[], const int lMA) "byte[]"
%typemap(jni) (signed char arrMA[], const int lMA) "jbyteArray"
%typemap(javain) (signed char arrMA[], const int lMA) "$javainput"
%typemap(in, numinputs=1) (signed char arrMA[], const int lMA) {
$1 = JCALL2(GetByteArrayElements, jenv, $input, NULL);
$2 = JCALL1(GetArrayLength, jenv, $input);
}
%typemap(freearg) (signed char arrMA[], const int lMA) {
JCALL3(ReleaseByteArrayElements, jenv, $input, $1, 0);
}
%typemap(jtype) (signed char arrMALIn[], int lMALIn) "byte[]"
%typemap(jstype) (signed char arrMALIn[], int lMALIn) "byte[]"
%typemap(jni) (signed char arrMALIn[], int lMALIn) "jbyteArray"
%typemap(javain) (signed char arrMALIn[], int lMALIn) "$javainput"
%typemap(in, numinputs=1) (signed char arrMALIn[], int lMALIn) {
$1 = JCALL2(GetByteArrayElements, jenv, $input, NULL);
$2 = JCALL1(GetArrayLength, jenv, $input);
}
%typemap(freearg) (signed char arrMALIn[], int lMALIn) {
JCALL3(ReleaseByteArrayElements, jenv, $input, $1, JNI_ABORT);
}
%typemap(jtype) bool modifyArrayLength "byte[]"
%typemap(jstype) bool modifyArrayLength "byte[]"
%typemap(jni) bool modifyArrayLength "jbyteArray"
%typemap(javaout) bool modifyArrayLength { return $jnicall; }
%typemap(in, numinputs=0) signed char ** arrMALOut (signed char * temp) "$1=&temp;"
%typemap(in, numinputs=0) int * lMALOut (int l) "$1=&l;"
%typemap(argout) (signed char ** arrMALOut, int * lMALOut) {
$result = JCALL1(NewByteArray, jenv, *$2);
JCALL4(SetByteArrayRegion, jenv, $result, 0, *$2, (const jbyte*) *$1);
}
%typemap(out) bool modifyArrayLength {
if (!$1) {
return NULL;
}
}
%include "arrays.h"
そして最後にJavaコードそれ:
public class Run{
static {
System.loadLibrary("Arrays");
}
public static void main(String[] args){
byte[] test = arrays.createArray();
printArray(test);
arrays.readArray(test);
arrays.modifyArrayValues(test);
printArray(test);
byte[] test2 = arrays.modifyArrayLength(test);
printArray(test2);
}
private static void printArray(byte[] arr){
System.out.println("Array ref: " + arr);
if(arr != null){
System.out.println("Array length: " + arr.length);
System.out.print("Arrays items: ");
for(int i =0; i < arr.length; i++){
System.out.print(arr[i] + " ");
}
}
System.out.println();
}
}
例に動作しますが、私はそれが正しい方法であることを確認しないんだけど、私は意味:
同じ結果を達成するための簡単な方法はありますか?
このコードはメモリリークを持っていますか?(私はcallocを実行するが、私はそれを解放しないが、もう一方ではSetByteArrayRegionに渡すので、エラー)?
SetByteArrayRegionは値をコピーするか、参照のみをコピーするのですか?たとえば、実際にcallocを実行する代わりに、スコープを終了したときに破棄される参照によってC++オブジェクトから配列を取得する場合は?
は、無効にすると正しく解放されたJavaに返される配列ですか?
typemapがどこからどこに適用されるのかを指定する方法はありますか?iコードでは、各関数のtypemapを提供していますが、それらのいくつかを再利用できると思いますが、他のものは同じパラメータを使って機能しますが、それらをtypemapしたくないのですが、どうすれば関数のパラメータ名を変更できないかもしれません。
私はこの質問How do I pass arrays from Java to C++ using Swig?に記載されているcarrays.i可能性を見てきましたが、それは配列のサイズが1000項目で、Javaソケット経由で送信したい場合や、各配列項目に対して1つのJNI呼び出しを行います。そして、私は実際には、Java側ではbyte[]
を、アンダーレイ配列にアクセスする関数のセットではないので、既存のコードは変更なしで動作します。
コンテキスト: 私はこれを達成したい理由は、いくつかの機能を持っているライブラリが存在することであるが、ここで重要な部分は、それがグーグルのライブラリ生かしからデータをインポートおよびエクスポートすることが可能であることですプロトコルバッファ。
class SomeLibrary {
bool export(const std::string & sName, std::string & toExport);
bool import(const std::string & sName, const std::string & toImport);
}
事はC++でいるProtobufは、データを格納するためのstd ::文字列を使用していることですが、それは通常のJavaのように戻すことはできませんので、このデータはバイナリです:だから、この質問に関連するコードは次のようになります文字列が切り詰められるため、Swig: convert return type std::string(binary) to java byte[]ではより多くの文字列が得られます。
私の考えは、シリアル化されたProtobuf(プロトコルバッファのJava版と同じように)のbyte[]
にJavaに戻り、protobufsを解析するためにbyte[]
を受け入れることです。輸出の第2引数にSWIGTYPE_p_std_string
を取得し、%を使用して両方の機能をラップしている輸入yの第二引数の文字列を避けるこのように、拡張するには:
%extend SomeLibrary{
bool export(const std::string & sName, char ** toExportData, int * toExportLength);
bool import(const std::string & sName, char * toImportData, int toImportLength);
}
を、今私は、タイプマップを作ることができるはずです。
しかし、より一般的には、私はJavaからSWIGへの配列の操作の一般的な質問ネイティブJava byte[]
を持っています。
:http://swig.org/Doc3.0/SWIGDocumentation.html#Java_binary_char
以下のインタフェースファイルは、Javaのバイト[]メソッドが生成されます。私はあなたがJavaで大きな配列を作成し、それをC++関数に渡したいと思っているのを修正していますか?私はそれに簡単な解決策を示し、あまりにもうまくいけば、他の質問のいくつかに対処することができます。例えば、 'void []'を 'void foo(const char * arr、size_t len);のような関数に渡そうとしていますか? – Flexo
@Flexo - 私はそれもやっていると思うよ。私は文脈をもう少し詳しく説明しています。 –
さらに多くの点に答えるには、 'SetByteArrayRegion'がデータをコピーします。 Java配列は、通常のJavaメカニズムによって管理されます。 JNIコールのローカルに作成され、最後の参照が削除された後、ある時点で解放されます。 – Flexo