在C语言开发中,内存操作是最基础也是最重要的技能之一。memmove作为标准库<string.h>中提供的内存操作函数,其核心功能是实现安全的内存区域拷贝。与memcpy不同,memmove专门设计用于处理源内存和目标内存区域可能存在重叠的情况。
重要提示:在不确定内存区域是否重叠时,memmove总是比memcpy更安全的选择。这也是为什么很多资深开发者建议在大多数情况下优先使用memmove。
memmove的函数原型如下:
c复制void *memmove(void *dest, const void *src, size_t n);
| 参数 | 类型 | 说明 |
|---|---|---|
| dest | void* | 目标内存地址指针 |
| src | const void* | 源内存地址指针 |
| n | size_t | 要拷贝的字节数 |
函数返回目标内存的起始地址dest。这种设计支持链式调用,例如:
c复制char buffer[100];
memcpy(memmove(buffer, src, 50) + 50, src2, 50);
c复制#include <stdio.h>
#include <string.h>
int main() {
char src[] = "安全内存拷贝示例";
char dest[50];
memmove(dest, src, strlen(src)+1);
printf("拷贝结果: %s\n", dest);
return 0;
}
这是memmove最核心的特性。考虑以下场景:
c复制char str[] = "abcdefgh";
// 将前4个字符移动到从第3个字符开始的位置
memmove(str+2, str, 4);
这种情况下,源区域(str[0]-str[3])和目标区域(str[2]-str[5])存在重叠,memcpy会导致数据错误,而memmove能正确处理。
虽然memmove功能更强大,但通常会有轻微的性能开销:
| 函数 | 平均执行时间(100MB数据) | 内存占用 |
|---|---|---|
| memcpy | 120ms | 低 |
| memmove | 135ms | 低 |
使用memcpy的情况:
使用memmove的情况:
memmove的核心算法是:
c复制void* my_memmove(void* dest, const void* src, size_t n) {
unsigned char* d = (unsigned char*)dest;
const unsigned char* s = (const unsigned char*)src;
if (d == s) return dest;
if (d < s || d >= s + n) {
// 无重叠或dest在src左侧,正向拷贝
for (size_t i = 0; i < n; i++)
d[i] = s[i];
} else {
// 有重叠且dest在src右侧,反向拷贝
for (size_t i = n; i > 0; i--)
d[i-1] = s[i-1];
}
return dest;
}
c复制typedef struct {
int id;
char name[20];
float score;
} Student;
void copy_student(Student* dest, const Student* src) {
memmove(dest, src, sizeof(Student));
}
memmove特别适合处理环形缓冲区中的数据搬移:
c复制void shift_buffer(char* buf, size_t size, size_t shift) {
memmove(buf, buf + shift, size - shift);
}
c复制// 错误:忘记乘以元素大小
int arr1[10], arr2[10];
memmove(arr2, arr1, 10); // 应该是10*sizeof(int)
c复制char small_buf[10];
char big_str[] = "这个字符串太长了";
memmove(small_buf, big_str, strlen(big_str)+1); // 缓冲区溢出
不同平台的memmove实现可能有差异:
在实际项目中,我遇到过ARM平台上一个memmove性能问题,最终发现是内存对齐导致的。解决方案是确保关键数据结构按4字节对齐,性能提升了近3倍。