Derek
Derek

Reputation: 11915

map return type of C++ function to byte[][] in Java

I have a c++ function declared as

unsigned char** classify

I am using the following interface file in SWIG

%module PWrap
%include "std_string.i"
%include "arrays_java.i"

%apply byte[][] {unsigned char**};

%{
#include "Classifier.h"
%}

%include "Classifier.h"

which generated some files, including a SWIGTYPE_p_p_unsigned_char object

Now, here's where I try to use this C++ function in Java:

SWIGTYPE_p_p_unsigned_char data = pc.classify();//this works, but I can't do anything with the data object execept pass it to other C++ functions expecting unsigned char**
byte[][] data2 =pc.classify();//this does not work - throws compile time error

So what am I doing wrong to get this mapping working correctly? I know the dimensions of the matrix, because I pass in the args to the C++ function to set everything up. In other words, I'd be happy with getting the data back in any way as long as I could cast it to byte somehow back in Java.

Upvotes: 2

Views: 923

Answers (3)

southerton81
southerton81

Reputation: 1109

Have a look at http://www.ibiblio.org/pub/languages/fortran/append-c.html "Why a double pointer can't be used as a 2D array?"

Upvotes: 1

ssmir
ssmir

Reputation: 1542

I'd better use use direct JNI instead of SWIG to have full control over such data types.

Anyway returning char ** is not effective because array pinning can't be used. Probably that's why your SWIG wrapper does not do what you want - your classify should accept char ** as a parameter and not return it. I don't know SWIG so here is some JNI code.

Java source:

package my;

public class Classifier {
    public native void init(); // initialize _ptr with a new Classifier
    public native void cleanup(); // destroy Classifier
    public native byte[][] classify();
    private long _ptr;
}

Method definition in C/C++:

Classifier *getClassifierInstance(JNIEnv *env, jobject obj) {
    jfieldID id = env->GetFieldID(env->GetObjectClass(obj), "_ptr", "J");
    return (id == NULL) ? NULL : ((Classifier *)env->GetLongField(obj, id));
}

JNIEXPORT jobjectArray JNICALL
Java_my_Classifier_classify(JNIEnv *env, jobject obj) {
    Classifier *classifier = getClassifierInstance(env, obj);
    char **ptr = classifier->classify();
    jobjectArray result = NewObjectArray(env, MATRIX_HEIGHT, FindClass(env, "[B"), NewByteArray(env, 0));
    for (int i = 0; i < MATRIX_HEIGHT; ++i) {
        jbyteArray row = NewByteArray(env, MATRIX_WIDTH);
        SetByteArrayRegion(env, row, 0, MATRIX_WIDTH, ptr[i]);
        SetObjectArrayElement(env, result, i, row);
    }
    return result;
}

Upvotes: 2

Puppy
Puppy

Reputation: 146940

A char** is not a byte[][]. Only single-dimensional arrays can decay into pointers. What you have got back is an array of pointers to arrays, not an array of arrays.

Upvotes: 3

Related Questions