阿里云手机应用开发,调用JNI接口,调用memcpy()函数出错。

yjx279742048 2012-07-31 04:17:01
JNI接口的实现中,有一段代码,功能是从一副图片中截取中间一部分,具体实现是这样的:
unsigned char *fun(unsigned char *data, int width, int height, int leftTopX, int leftTopY, int nWidth, int nheight)
//data, 图片内存首地址,width, height, 图片宽和高;
//leftTopX, leftTopY,截取区域左上角的点坐标
//nWidth, nHeight, 截取区域的宽和高
{
unsigned char *temp, *tempN;
unsigned char *pxl;
int size = nWidth * nHeight;
pxl = NULL;
if ((pxl = (unsigned char *)malloc(size * sizeof(unsigned char))) == NULL)
{
return NULL;
}
memset(readImg->pxl, 0x00, sizeof(size * sizeof(unsigned char)));
temp = data + width * leftTopY + leftTopX;
tempN = pxl;
for (i = 0; i < nHeight; i++)
{
__android_log_print(ANDROID_LOG_INFO, "[hello-jni.c]", "i is %d", i);
memcpy(tempN, temp, nWidth);
__android_log_write(ANDROID_LOG_INFO, "[hello-jni.c]", "123456789_0");
temp += width;
__android_log_write(ANDROID_LOG_INFO, "[hello-jni.c]", "123456789_1");
tempN += nWidth;
__android_log_write(ANDROID_LOG_INFO, "[hello-jni.c]", "123456789_2");
}

return pxl;
}

上面是这部分完整的代码,这个应用在大部分android手机上都没有问题,但在阿里云手机上就会出错。出现的问题是这样的,
假设nHeight是200,那要循环200次,可是从log上看,每次出错都是循环没有运行完,而且是memcpy这一句出错。

请大侠帮忙看看,问题怎么解决?
...全文
299 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
yjx279742048 2012-08-09
  • 打赏
  • 举报
回复
谢谢大家了,问题以解决,结贴了,
Gonefar 2012-08-05
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 的回复:]

多谢谢大家的提示,我现在发现这个问题,我的接口是这样的:
unsigned char *fun(unsigned char *data, int width, int height, int leftTopX, int leftTopY, int nWidth, int nheight);
按正常思路,data所指向空间的大小应该和width、height匹配。
我最初想的是空间大小应该等……
[/Quote]
由于对计算机硬件不是很清楚,很多问题可能弄的不是很明白。我提些建议:你的内存与width*height是怎样的对应关系,当然,最好是弄清楚,不清楚的话,一般适当分配多一些内存。计算机内部会有字节对齐,预留空间之类的。所以尽量分配足够的空间。
yjx279742048 2012-08-02
  • 打赏
  • 举报
回复
多谢谢了,我再细查一下。
还有就是,前面的代码中,我是一行一行复制内存的,现在我把它改成一个字节一个字节的copy值,还是必出现循环没有做完就退出,所以我觉得根源还是在空间是否足够这一块。

[Quote=引用 8 楼 的回复:]

引用 7 楼 的回复:

我也觉得你说的这个有道理,只是前面给pxl申请空间时,指定的大小是足够的,如果申请不成功会提前退出,data是传进来的参数,data、temp、width一组,pxl、tempN、nWidth一组,单看log上打印的每次循环时的指针值,我查了十几个,都没有问题。你说的看两者的地址空间是否足够,怎么来验证呢?
谢谢。

引用 6 楼 的回复:

循环次数……
[/Quote]
Alexander 2012-08-02
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 的回复:]

我也觉得你说的这个有道理,只是前面给pxl申请空间时,指定的大小是足够的,如果申请不成功会提前退出,data是传进来的参数,data、temp、width一组,pxl、tempN、nWidth一组,单看log上打印的每次循环时的指针值,我查了十几个,都没有问题。你说的看两者的地址空间是否足够,怎么来验证呢?
谢谢。

引用 6 楼 的回复:

循环次数多了就出问题,那么必然出在循环里……
[/Quote]
在下知道这不是问题的关键,但还是给LZ说个细节:
malloc函数在申请失败时并不一定会返回NULL,判断申请失败似乎要用到stderr。(PS:具体方法在下也不太清楚,可以百度一下)
yjx279742048 2012-08-02
  • 打赏
  • 举报
回复
我也觉得你说的这个有道理,只是前面给pxl申请空间时,指定的大小是足够的,如果申请不成功会提前退出,data是传进来的参数,data、temp、width一组,pxl、tempN、nWidth一组,单看log上打印的每次循环时的指针值,我查了十几个,都没有问题。你说的看两者的地址空间是否足够,怎么来验证呢?
谢谢。

[Quote=引用 6 楼 的回复:]

循环次数多了就出问题,那么必然出在循环里。而是因为次数大了出问题,那必然是因为地址在不断递进过程中出问题了!我觉得还是我楼上回答的那样。LZ仔细看看temp += width与tempN += nWidth,两者的地址空间是否够用?是否其中一个或两个在循环200多次后,地址空间就用完了。
[/Quote]
yjx279742048 2012-08-02
  • 打赏
  • 举报
回复
多谢谢大家的提示,我现在发现这个问题,我的接口是这样的:
unsigned char *fun(unsigned char *data, int width, int height, int leftTopX, int leftTopY, int nWidth, int nheight);
按正常思路,data所指向空间的大小应该和width、height匹配。
我最初想的是空间大小应该等于width*height。
但实际中发现不是这样的。我这试了三款手机,A和B上运行正常,C上运行错误,就是前面提到的那些问题。
A机的三个值:空间大小614800,width854, height480;
B机的三个值:空间大小514800,width720, height480;
C机的三个值:空间大小115200,width800, height448;
这些值都是Java调用端得到的。

分析这三组值,发现
614800 > 854 * 480; 614800 / 2 == 854 * 480;
514800 > 720 * 480; 514800 / 2 == 720 * 480;
115200 < 800 * 448;

现在想不通的是,为什么空间大小不等于width*height,这些可都是8位灰度图啊。
yjx279742048 2012-08-01
  • 打赏
  • 举报
回复
我把运行过程中所有的参数都打印出来了,data,pxl,temp,tempN四个指针用十六进制的形式打印。
同步应该没有问题。
下面是log里的内容:

01-02 04:36:42.870: W/System.err(3364): width:800
01-02 04:36:42.870: I/[hello-jni.c](3364): data is 407591e8
01-02 04:36:42.870: I/[hello-jni.c](3364): size is 67200
01-02 04:36:42.870: I/[hello-jni.c](3364): pxl is 40040008
01-02 04:36:42.870: I/[hello-jni.c](3364): width is 800,
01-02 04:36:42.870: I/[hello-jni.c](3364): height is 448,
01-02 04:36:42.870: I/[hello-jni.c](3364): nWidth is 200,
01-02 04:36:42.870: I/[hello-jni.c](3364): nHeight is 336,
01-02 04:36:42.870: I/[hello-jni.c](3364): leftTopX is 300,
01-02 04:36:42.870: I/[hello-jni.c](3364): leftTopY is 56,
01-02 04:36:42.870: I/[hello-jni.c](3364): i is 0
01-02 04:36:42.870: I/[hello-jni.c](3364): temp is 40764214, tempN is 40040008
01-02 04:36:42.870: I/[hello-jni.c](3364): 123456789_0
01-02 04:36:42.870: I/[hello-jni.c](3364): 123456789_1
01-02 04:36:42.870: I/[hello-jni.c](3364): 123456789_2
01-02 04:36:42.870: I/[hello-jni.c](3364): i is 1
01-02 04:36:42.870: I/[hello-jni.c](3364): temp is 40764534, tempN is 400400d0
01-02 04:36:42.870: I/[hello-jni.c](3364): 123456789_0
01-02 04:36:42.870: I/[hello-jni.c](3364): 123456789_1
01-02 04:36:42.870: I/[hello-jni.c](3364): 123456789_2
01-02 04:36:42.870: I/[hello-jni.c](3364): i is 2
01-02 04:36:42.870: I/[hello-jni.c](3364): temp is 40764854, tempN is 40040198
01-02 04:36:42.870: I/[hello-jni.c](3364): 123456789_0
01-02 04:36:42.870: I/[hello-jni.c](3364): 123456789_1
01-02 04:36:42.870: I/[hello-jni.c](3364): 123456789_2
……
……
……
01-02 04:36:42.870: I/[hello-jni.c](3364): i is 213
01-02 04:36:42.870: I/[hello-jni.c](3364): temp is 4078dbb4, tempN is 4004a670
01-02 04:36:42.870: I/[hello-jni.c](3364): 123456789_0
01-02 04:36:42.870: I/[hello-jni.c](3364): 123456789_1
01-02 04:36:42.870: I/[hello-jni.c](3364): 123456789_2
01-02 04:36:42.870: I/[hello-jni.c](3364): i is 214
01-02 04:36:42.870: I/[hello-jni.c](3364): temp is 4078ded4, tempN is 4004a738
01-02 04:36:42.870: I/[hello-jni.c](3364): 123456789_0
01-02 04:36:42.870: I/[hello-jni.c](3364): 123456789_1
01-02 04:36:42.870: I/[hello-jni.c](3364): 123456789_2
01-02 04:36:42.870: I/[hello-jni.c](3364): i is 215
01-02 04:36:42.900: V/NvOmxCamera(19858): First preview frame displayed
01-02 04:36:42.900: V/NvOmxCamera(19858): ReleaseWakeLock
01-02 04:36:42.900: V/NvOmxCamera(19858): NvOmxCamera::NvOmxCameraGraphEventHandler --

输入data地址为0x407591e8;pxl初始化为0x40040008;size大小是67200,是200*336,
第一次循环:
temp是0x40764214, 0x40764214 == 0x407591e8(data) + 800(width) * 56(leftTopY ) + 300(leftTopX),
tempN是0x40040008,0x40040008 == 0x40040008;
第二次循环:
temp: 0x40764534 - 0x40764214 == 800(width);
tempN: 0x400400d0 - 0x40040008 == 200(nWidth);

从这些参数里都看不出问题。

循环到215次时就出错了,memcpy()那一句后面的log都没有打印出来。
Gonefar 2012-08-01
  • 打赏
  • 举报
回复
循环次数多了就出问题,那么必然出在循环里。而是因为次数大了出问题,那必然是因为地址在不断递进过程中出问题了!我觉得还是我楼上回答的那样。LZ仔细看看temp += width与tempN += nWidth,两者的地址空间是否够用?是否其中一个或两个在循环200多次后,地址空间就用完了。
yjx279742048 2012-08-01
  • 打赏
  • 举报
回复
噢,谢谢,这一句是我发贴的时候弄错了,
memset(readImg->pxl, 0x00, sizeof(size * sizeof(unsigned char)));
这一句应该是
memset(pxl, 0x00, sizeof(size * sizeof(unsigned char)));

贴子上的代码是我整理过的,这一句是我发贴的时候弄错了,不应该是这里的问题的。
整个程序在很多型号的android手机上都测过,没发现问题,现在就是在阿里云的手机上运行时发现有问题。
zunceng 2012-08-01
  • 打赏
  • 举报
回复
感觉问题是在readImg->pxl这个全局变量上 悬空指针了可能
yjx279742048 2012-08-01
  • 打赏
  • 举报
回复
我又试了一下,把这一段先给屏了,测后面的代码,发现还有这些问题:
1,memcpy()函数,参数size值大的情况下,会出错,其后的log打印不出来。
比如copy一幅图片的内存,一次copy整幅图的话,就出错了,
分成一行一行copy的话,就可以运行下去。
2,接问题1,一幅图一行一行copy,需要循环height次,
这里我的height是448,一般循环到200多次的时候会挂掉。
这些都 是从log上看出来的。
Gonefar 2012-07-31
  • 打赏
  • 举报
回复
temp += width;与tempN += nWidth;的地址同步了吗?否则一个地址用完了,而另一个没用完,就会出错。导致指针越界。

69,371

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧