【问题标题】:How to pass a 3D element into JNI?如何将 3D 元素传递给 JNI?
【发布时间】:2022-06-10 21:52:56
【问题描述】:

我正在做一个项目,需要在 C++ 中使用 3D 数组进行一些计算。我需要将这个 3D 数组从 Java 传递到 C++,进行一些计算,然后返回它。我正在使用 JNI 并且对它很陌生,所以我不太了解。我正在尝试制作一个示例程序来测试它并将其用作参考。我已经将 2D 数组传递给 C++,但无法弄清楚 3D 部分。我使用 this solution 构建了 2D 部分。

这是我现在的 C++ 代码(适用于二维数组):

float*** testFunction(float ***a)
{

printf("Hello from JNI!\n");
    printf("Point at %d,%d,%d is: %f\n", 1, 2, 2, a[1][2]);

    return a[1][2][2];
}
jfloat JNICALL Java_JNIArray_integrateWithTrapezoid(JNIEnv *env, jobject thisObj, jobjectArray jarr)
{
    int sizex = env->GetArrayLength(jarr);
    jfloatArray dim = (jfloatArray)env->GetObjectArrayElement(jarr, 0);
    int sizey = env->GetArrayLength(dim);
    float **localArray;

    localArray = new float *[sizex];

    for (int i = 0; i < sizex; i++)
    {
        jfloatArray oneDim = (jfloatArray)env->GetObjectArrayElement(jarr, i);
        jfloat *element = env->GetFloatArrayElements(oneDim, 0);
        localArray[i] = new float[sizey];

        for (int j = 0; j < sizey; j++)
        {
            localArray[i][j] = element[j];
        }
    }

    return trapezoidalintegral(localArray);
}

任何帮助都会很棒。我对此一无所知。如果我忘记提供任何需要的信息,请告诉我。

谢谢。

编辑:

感谢@Botje,这成功了:

void trapezoidalintegral(float ***a)
{

    printf("Hello from JNI!\n");
    printf("Point at %d, %d, %d is: %f\n", 1, 2, 2, a[1][2][2]);

    return;
}

float *thirdLevel(JNIEnv *env, jfloatArray arr)
{
    jsize len = env->GetArrayLength(arr);
    float *ret = new float[len];
    env->GetFloatArrayRegion(arr, 0, len, ret);
    return ret;
}

float **secondLevel(JNIEnv *env, jobjectArray arr)
{
    jsize len = env->GetArrayLength(arr);
    float **ret = new float *[len];
    for (int i = 0; i < len; i++)
    {
        jobject item = env->GetObjectArrayElement(arr, i);
        ret[i] = thirdLevel(env, (jfloatArray)item);
        env->DeleteLocalRef(item);
    }
    return ret;
}

float ***firstLevel(JNIEnv *env, jobjectArray arr)
{
    jsize len = env->GetArrayLength(arr);
    float ***ret = new float **[len];
    for (int i = 0; i < len; i++)
    {
        jobject item = env->GetObjectArrayElement(arr, i);
        ret[i] = secondLevel(env, (jobjectArray)item);
        env->DeleteLocalRef(item);
    }
    return ret;
}

JNIEXPORT jobjectArray JNICALL Java_JNIArray_integrateWithTrapezoid(JNIEnv *env, jobject thisObj, jobjectArray jarr)
{
    float ***returningArray;

    returningArray = firstLevel(env, jarr);

    trapezoidalintegral(returningArray);

    jclass *pClass;
    jclass cls1;
    jclass jcls1;
    jclass jcls2;
    jobject obj2;

    cls1 = env->GetObjectClass(thisObj);
    // jfieldID fid1 = env->GetFieldID(cls1, "ptr", "J");
    // pClass = (jclass *)env->GetLongField(thisObj, fid1);

    jcls1 = env->FindClass("[[F");
    jcls2 = env->FindClass("[F");

    jobjectArray array1 = env->NewObjectArray(3, jcls1, NULL);

    for (int i = 0; i < 3; i++)
    {
        jobjectArray array2 = env->NewObjectArray(3, jcls2, NULL);

        for (int j = 0; j < 3; j++)
        {
            jfloatArray array3 = env->NewFloatArray(3);
            env->SetFloatArrayRegion(array3, 0, 3, returningArray[i][j]);
            env->SetObjectArrayElement(array2, j, array3);
        }

        env->SetObjectArrayElement(array1, i, array2);
    }

    env->DeleteLocalRef(cls1);
    env->DeleteLocalRef(jcls1);
    env->DeleteLocalRef(jcls2);

    return array1;
}

【问题讨论】:

  • 锯齿状 3D 数组与锯齿状 2D 数组相同,中间填充了额外的指针数组。 float **localArray = new float **[sizex];,然后是一个将new float *[sizey]; 放入localarray 的循环,然后是另一个将new float[sizez]s 放入每个float* 数组的循环。像一样丑陋,不是吗?而是考虑一个庞大的 1D 数组并使用索引数学来假装它是 3D。
  • @user4581301 我不会像float ***localArray = new float**[sizex];那样初始化数组吗?
  • 是的。对于那个很抱歉。当我剪切、粘贴和更新时错过了开始..

标签: java c++ java-native-interface


【解决方案1】:

就像你的数据一样构建你的程序:

float* thirdLevel(JNIEnv *env, jfloatArray arr) {
  jsize len = env->GetArrayLength(arr);
  float* ret = new float[len];
  env->GetFloatArrayRegion(arr, 0, len, ret);
  return ret;
}

float** secondLevel(JNIEnv *env, jobjectArray arr) {
  jsize len = env->GetArrayLength(arr);
  float** ret = new float*[len];
  for (int i = 0; i < len; i++) {
    jobject item = env->GetObjectArrayElement(arr, i);
    ret[i] = thirdLevel(env, (jfloatArray)item);
    env->DeleteLocalRef(item);
  }
  return ret;
}

float*** firstLevel(JNIEnv *env, jobjectArray arr) {
  jsize len = env->GetArrayLength(arr);
  float*** ret = new float**[len];
  for (int i = 0; i < len; i++) {
    jobject item = env->GetObjectArrayElement(arr, i);
    ret[i] = secondLevel(env, (jobjectArray)item);
    env->DeleteLocalRef(item);
  }
  return ret;
}

【讨论】:

  • 我更新了答案以显示我的实现以及错误消息。我在这里做错了什么?我很确定我返回了正确的数据类型,所以我不确定为什么会收到此错误消息。
  • 你的头文件承诺你会返回一个jobjectArray,而你的cpp文件承诺会返回一个float***(Java不能做任何有用的事情)。
  • 你想让Java_JNIArray_integrateWithTrapezoid返回什么?从函数名称来看,我认为您只需要一个 jfloat
  • 我更新了答案,所以它更有意义 - 整合梯形只是我以前使用的一种测试方法,所以我实际上不会整合任何东西,应该澄清这一点。我还需要返回一个 3D 数组。我很确定我现在的问题只是从 float*** 转换为 jobjectarray,我也不知道该怎么做。
  • 反向路径已经覆盖here
猜你喜欢
  • 2019-11-09
  • 1970-01-01
  • 1970-01-01
  • 2016-08-03
  • 2016-03-25
  • 1970-01-01
  • 2018-06-22
  • 2021-05-16
  • 1970-01-01
相关资源
最近更新 更多