【问题标题】:The address of the pointer changes when passed to a C function below the JNI layer指针的地址在传递给 JNI 层以下的 C 函数时发生变化
【发布时间】:2016-08-01 13:34:03
【问题描述】:

我正在尝试使用 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().
  • 我尝试用%d 打印它的值,它为我打印了 1,这是意料之中的。
  • 无论如何,你能发布segment_offline()的定义吗?你为什么要使用cast to int *?函数已经有正确的返回类型。
  • 我已经发布了segment_offilne() 的定义并标记了我得到分段错误的地方。
  • JNI 规定 jint/jfloat/jdouble 的大小为 32/32/64 位。您确定这与您运行它的任何架构上的 C int/float/double 类型的大小相匹配吗?

标签: android c pointers android-ndk java-native-interface


【解决方案1】:

只是猜测。有人在取消推荐之前破坏了您的num_segments。尝试在函数开始时立即打印其值,然后在崩溃线之前。崩溃日志还显示SIGSEGV 出现在地址0x60000000 上,这不太可能是堆栈对象的地址。

编辑

不正确的参数值也可能是由调用不正确声明的函数引起的,即如果您调用了尚未定义或在另一个翻译单元中定义的函数 - 您必须提供前向声明,告知编译器实际参数列表和返回类型。请注意,C89 允许隐式函数声明。如果您不声明该函数 - 编译器假定它具有 int 返回类型并采用任意数量的任何参数。 See here for details。请注意,定义和调用签名的不匹配会导致未定义的行为。

附:此外,没有前向声明可能会迫使您强制转换函数返回,因为编译器期望它是 int

【讨论】:

  • 我不这么认为,因为除了取消引用它之外,我没有在其他任何地方使用过这个指针变量。无论如何,谢谢你的想法。
  • 只是一个更正。当我将地址传递给 JNI 层下的 C 函数时,地址实际上正在被修改。所以JNI层中的值为:Address in the JNI function: 0x9e192784,输入segment_offilne()后的值为After just entering the function: 0x60000000。我现在不知何故觉得这不是解决这个问题的正确方法。是吗?
  • 听起来像 ABI 问题。 JNI函数前是否有segment_offline()的转发声明(或定义)?
  • 哇...这是错误的。我有一个头文件,但我没有包含在 JNI 函数文件中(尽管它包含在我的 segment_offilne()function 定义的文件中。这是什么原因?你能指出一些资源吗?) .万分感谢。您能否修改答案以说出这一点,我也会更改问题并接受您的答案。
猜你喜欢
  • 2020-01-09
  • 1970-01-01
  • 2019-07-17
  • 1970-01-01
  • 2021-12-27
  • 2019-07-26
  • 1970-01-01
  • 1970-01-01
  • 2013-05-14
相关资源
最近更新 更多