通过JNI层传递给C函数的指针地址会发生变化。

3

我正在尝试使用NDK在Android中编写本地C代码。我有一个函数segment_offline(),它接受许多参数,包括整数指针int * num_segments。我想要这个指针,因为我想在我的C函数中读取此指针所指向的整数值,该函数作为我的JNI接口。以下是segment_offline()的代码:

int * segment_offline(const SEGMENT_DATATYPE *x, const int num_samples_x, const float *svara_cents, const int *svara_lengths, const int num_svaras, const int type, const int hop_size, const float tonic, int *num_segments) {

int i;

// using DTW ...
if (0 == type) {

    filtered_samples_t fns;

    // removing the negative frequencies in Hz.
    filter_negative_samples(x, num_samples_x, &fns);

    __android_log_print(ANDROID_LOG_DEBUG, "LogNDK", "After filter_negative_samples\n");

    // converting the Hz to Cents
    convert_pitch_to_cents(fns.arr_filtered, fns.len, tonic);

    __android_log_print(ANDROID_LOG_DEBUG, "LogNDK", "After convert_pitch_to_cents\n");

    //print_double_array(fns.arr_filtered, fns.len);
    segments_t seg = segment_offline_dtw(fns.arr_filtered, fns.len, svara_cents, svara_lengths, num_svaras, hop_size);

    __android_log_print(ANDROID_LOG_DEBUG, "LogNDK", "After segment_offline_dtw\n");

    int * ret_segments = (int *) malloc(sizeof(seg.num_segments));

    __android_log_print(ANDROID_LOG_DEBUG, "LogNDK", "After allocating memory to ret_segments\n");

    // setting the value of the number of segments in the pointer that would be referred.
    // ########## I get a segmentation fault here #########
    __android_log_print(ANDROID_LOG_DEBUG, "LogNDK", "The number of segments are: %d\n", seg.num_segments);
    *num_segments = seg.num_segments;

    __android_log_print(ANDROID_LOG_DEBUG, "LogNDK", "After assigning the number of segments: %d\n", *num_segments);

    for (i = 0;i < seg.num_segments * 2; i++) {
        ret_segments[i] = fns.original_indices[seg.segments_pos[i]];
        printf("%d, ", ret_segments[i]);
    }
    printf("\n");

    __android_log_print(ANDROID_LOG_DEBUG, "LogNDK", "Returning from segment_offline\n");

    return ret_segments;
}

我编写的JNI C函数如下:

JNIEXPORT jintArray JNICALL Java_com_camut_audioiolib_dsp_DSPAlgorithms_segmentOffline
  (JNIEnv *env, jclass cls, jdoubleArray x, jint numSamples, jfloatArray svaraCents,
  jintArray svaraLengths, jint numSvaras, jint type, jint hopSize, jfloat tonic) {

    jdouble *xDouble = (*env)->GetDoubleArrayElements(env, x, NULL);
    jfloat *svaraCentsFloat = (*env)->GetFloatArrayElements(env, svaraCents, NULL);
    jint *svaraLengthsInt = (*env)->GetIntArrayElements(env, svaraLengths, NULL);

    __android_log_print(ANDROID_LOG_DEBUG, "LogNDK", "The size of the type tonic is: %d", sizeof(tonic));

    int num_segments;

    int * segments = (int *) segment_offline(xDouble, numSamples, svaraCentsFloat, svaraLengthsInt,
        numSvaras, type, hopSize, tonic, &num_segments);

    if (NULL == segments) {
       return NULL;
    }

    // releasing the allocated memories ...
    (*env)->ReleaseDoubleArrayElements(env, x, xDouble, JNI_ABORT);
    (*env)->ReleaseFloatArrayElements(env, svaraCents, svaraCentsFloat, JNI_ABORT);
    (*env)->ReleaseIntArrayElements(env, svaraLengths, svaraLengthsInt, JNI_ABORT);

     return NULL;

  }

你可以看到上面的代码中,我已经初始化了一个num_segments作为int变量,并将该变量的地址传递给上述函数。因此,似乎我无法对int指针进行解引用操作。你有什么建议吗?我需要这个指针,因为我正在返回其他值作为我的函数返回值。

seg.num_segments是什么?请发布完整的segment_offline()函数。 - Sergio
我尝试使用%d打印它的值,结果打印出1,这是可以预料的。 - Swapnil
无论如何,你能发布segment_offline()的定义吗?另外为什么要使用int *类型转换?函数已经有了正确的返回类型。 - Sergio
我已发布了 segment_offline() 的定义,并标记了我遇到分段错误的地方。 - Swapnil
JNI规定jint/jfloat/jdouble的大小为32/32/64位。您确定这与您正在运行的任何架构上的C int/float/double类型的大小相匹配吗? - Michael
1个回答

2
只是猜测,可能在解除引用之前,某人会损坏您的num_segments。尝试在函数开始时立即打印其值,然后在崩溃行之前再次打印其值。此外,崩溃日志显示SIGSEGV发生在地址0x60000000,这不太可能是堆栈对象的地址。
编辑:调用声明不正确的函数可能会导致参数值不正确,例如如果您调用尚未定义或在另一个翻译单元中定义的函数,则必须提供前向声明,告诉编译器有关实际参数列表和返回类型的信息。请注意,C89允许隐式函数声明。如果您不声明函数,则编译器假定它具有int返回类型并且需要任意数量的任何参数。详情请参见此处。请注意,定义和调用签名不匹配会导致未定义行为。
另外,缺少前向声明也可能会强制您转换函数返回,因为编译器期望它是int

我不这么认为,因为除了解引用它之外,我没有在其他任何地方使用过这个指针变量。无论如何,感谢您的想法。 - Swapnil
只是一个更正。当我将地址传递到JNI层下面的C函数时,实际上地址正在被修改。因此,在JNI层中的值为:JNI函数中的地址:0x9e192784,而在进入segment_offline()函数后的值为刚进入函数后的值:0x60000000。我现在有些感觉这不是解决这个问题的正确方法。是吗? - Swapnil
听起来像是ABI问题。在JNI函数之前是否有segment_offline()的前向声明(或定义)? - Sergio
哇...那就是错误所在。我有一个头文件,但我没有在JNI函数文件中包含它(尽管它已经被包含在定义我的segment_offline()函数的文件中)。这是什么原因?你能指向一些相关资源吗?非常感谢。你能把答案修改一下,让我也能修改问题并接受你的答案吗? - Swapnil

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接