linux应用程序中的memcpy常见问题

linux中内存拷贝常用memcpy函数,但实际使用中发现坑很多,稍有不慎就会导致程序崩溃,直接退出。
因为在memcpy的底层实现中为了优化性能,ARM平台采用了int类型即4字节一次的拷贝,ARM64平台采用了int64_t类型即8字节一次的拷贝,这就造成可能出现以下问题:
1.问题1,拷贝的长度可能不是拷贝单位的倍数问题,导致最后一次数据对不上或者越界,可能造成程序崩溃。
这种情况一般是拷贝的时候计算一下长度是否是倍数,不足的单独拷贝,示例如下
if (length > 0 && data != NULL) {
int remainder = length % 8;
if(remainder !=0 ) {
length = length - remainder;

		memcpy(cp->upper_data, data, length);

		for(int i = 0; i<remainder; i++) {
			*(uint8_t *)(cp->upper_data + length + i) = *(uint8_t *)(data + length + i);
		}
	} else {
		memcpy(cp->upper_data, data, length);

	}
}

2.问题2,拷贝的起始地址不是平台拷贝单元的倍数问题,即地址不对齐,直接造成程序发生对齐异常而崩溃。
笔者在项目中需要拷贝一段ADC采样数据,根据不同的测试条件需要加一个偏移值,所以可能造成这个值就不再是8的倍数,导致一运行到此处程序就退出,
最终采用的是在memcpy直接把buf地址处理一下,掐去不对齐的部分:
{ //move buf to 8 bytes aligned
uint64_t addr = buf;
if(addr%8)
buf-=(addr%8);
}
3.问题3,分析上面问题2时求助AI发现的一种情况,未实际碰到过
memcpy对内存重叠的处理也存在风险,当源和目标内存区域有重叠时,memcpy的行为是未定义的,可能导致数据损坏或程序崩溃。
这种情况下应该使用memmove函数来确保数据正确性。

以上各种问题都用以下笨办法都没问题,但是效率低一些:
for(int i = 0; i<length; i++)
*(uint8_t *)(cp->upper_data + i) = *(uint8_t *)(data + i);

posted @ 2025-11-07 17:08  junghooqian  阅读(1)  评论(0)    收藏  举报