在JNI/Android-NDK中传递指针为jlong​​不起作用()

问题描述:

我正在开发一个低级Android库,它需要在JNI中处理音频信号以节省处理成本。因为我可能需要多次引用同一个音频缓冲区,所以我决定保留一个结构的指针来将这些音频缓冲区包含在C中(因此多个C函数可以访问相同的音频缓冲区)。我主要使用从herehere借来的想法。在JNI/Android-NDK中传递指针为jlong​​不起作用()

但是,事情并不按预期工作。我的程序在另一个函数试图访问先前的jni调用分配的内存后崩溃。

下面是JNI例子来说明这个问题:

struct AddAudioRet{ 
    int chCnt; 
    int traceCnt; 
    int sampleCnt; 
    float ***data; // data[chIdx][traceIdx][sampleIdx]; -> reverse order of the Matlab data structure 
}; 
extern "C" jlong Java_XXX_XXX_addAudioSamples(JNIEnv *env, jobject obj, jbyteArray audioToAdd) { 
    // some processing codes 
    AddAudioRet *ret; 
    ret = (AddAudioRet *)malloc(sizeof(AddAudioRet)); 
    ret->chCnt = ps->recordChCnt; // 2 
    ret->traceCnt = repeatToProcess; // 3 
    ret->sampleCnt = as->signalSize; // 2400 
    jlong retLong = (jlong)ret; 
    mylog("retLong (jlong) = %ld", retLong); 
    AddAudioRet *temp = (AddAudioRet *)retLong; 
    mylog("temp's chCnt %d, traceCnt %d, sampleCnt = %d", temp->chCnt, temp->traceCnt, temp->sampleCnt); 
    return retLong; // return the memory address of the ret structure 
} 

extern "C" void Java_XXX_XXX_debugDumpAddAudioRet(JNIEnv *env, jobject obj, jlong addAudioRet) { 
    debug("addAudioRetLong = %ld", addAudioRet); 
    debug("ret's chCnt %d, traceCnt %d, sampleCnt = %d", r->chCnt, r->traceCnt, r->sampleCnt); 
} 

在Android中,我称之为JNI函数是这样的:

public native int addAudioSamples(byte[] audioToAdd); 
public native void debugDumpAddAudioRet(long addAudioRet); 
int testJNI(byte[] data) { 
    long ret = addAudioSamples(data); 
    debugDumpAddAudioRet(ret); 
} 

结果:

retLong (jlong) = 547383410656 
temp's chCnt 2, traceCnt 3, sampleCnt = 2400 
// *** dumped by the debug check *** 
addAudioRetLong = 1922564064 
ret's chCnt 55646750, traceCnt 82374663, sampleCnt = 1831675530 

我知道问题是内存地址和jlong​​之间的类型转换,因为内存地址输出不相同。但是,我不知道它是如何发生的,如果转换不被允许/合法,当我(平凡地)转储“temp”变量时,我会得到错误,对吗?

+0

可能是尺寸问题。指针是64位的,但是长度往往只有32位 - 通常你需要用很长的时间来存储一个指针。 –

+0

嗨Gabe,我想这也是大小问题,但我确实打印了sizeof jlong​​(= 8字节),我确信java long也是> 8个字节(例如,long testLong = 547383410656L就可以了)。 –

我发现了这个问题。我的本地函数签名是错误的....

错误:

public native int addAudioSamples(byte[] audioToAdd); 

正确:

public native long addAudioSamples(byte[] audioToAdd); 

感到惊讶的是Java的似乎是相当聪明的帮我做某种功能自动重载。

+0

实际上,如果为同样的'extern“C”jlong​​ Java_XXX_XXX_addAudioSamples(JNIEnv * env,jobject obj,jbyteArray audioToAdd)'声明'native int addAudioSamples(String audioToAdd)',Java将无法捕捉到你。有一种方法可以声明重载的本地方法,但是:https://*.com/a/45024076/192373。 –