C语言学习笔记20260621-内存库函数模拟实现(memcpy与memmove)
一、学习目标
深入理解C语言底层内存操作的核心机制,掌握memcpy与memmove的底层实现原理。重点剖析void*泛型指针的字节级操作技巧,以及memmove在处理内存重叠时的双向拷贝逻辑,从而写出安全、健壮的底层代码。
二、模拟实现 memcpy(非重叠内存拷贝)
2.1 核心思路
memcpy的作用是从源内存地址向目标内存地址拷贝指定字节数的数据。由于内存中存储的数据类型是未知的,因此必须将指针强制转换为char*,以"字节"为最小单位进行逐字节搬运。
2.2 代码解析与规范
c
void* memcpy(void* dst, const void* src, size_t count)
{
void* ret = dst; // 保存目标内存的起始地址,用于函数返回
assert(dst); // 断言拦截空指针,保证代码健壮性
assert(src);
/* 从低地址向高地址逐字节拷贝 */
while (count--) {
*(char*)dst = *(char*)src; // 强转为char*,每次只拷贝1个字节
dst = (char*)dst + 1; // 指针向后偏移1个字节
src = (char*)src + 1;
}
return(ret);
}
2.3 关键细节与致命隐患
- void*的强制转换 :
void*不能直接解引用或进行加减运算。将其强转为char*是因为char在C语言中正好占用1个字节,配合count参数可以实现对任意类型数据的精准拷贝。 - 保存起始地址 :由于
dst指针在循环中不断向后偏移,最终会指向内存块的末尾。因此必须在开头用ret保存初始地址,以便支持链式调用。 - 致命隐患(内存重叠) :标准
memcpy严禁用于处理内存重叠的场景。如果目标区域和源区域有重叠,且目标地址位于源地址的高位,从前向后的拷贝会直接覆盖掉源内存中尚未拷贝的数据,导致数据错乱。
三、模拟实现 memmove(安全内存移动)
3.1 核心思路
memmove是memcpy的安全升级版,专门用于处理源内存与目标内存存在重叠的情况。其核心逻辑是:通过判断源地址和目标地址的相对位置,动态决定是"从前向后"拷贝,还是"从后向前"拷贝。
3.2 代码深度解析
c
void* memmove(void* dst, const void* src, size_t count)
{
void* ret = dst;
// 情况1:无重叠,或目标在源的前方(安全,可正向拷贝)
if (dst <= src || (char*)dst >= ((char*)src + count)) {
while (count--) {
*(char*)dst = *(char*)src;
dst = (char*)dst + 1;
src = (char*)src + 1;
}
}
// 情况2:发生重叠且目标在源的后方(必须反向拷贝)
else {
// 将指针先移动到内存块的末尾
dst = (char*)dst + count - 1;
src = (char*)src + count - 1;
// 从高地址向低地址逐字节拷贝
while (count--) {
*(char*)dst = *(char*)src;
dst = (char*)dst - 1; // 指针向前偏移
src = (char*)src - 1;
}
}
return(ret);
}
3.3 内存重叠的决策逻辑
- 正向拷贝(低地址 -> 高地址) :当
dst <= src(目标在源前面)或者两者完全不重叠时,源内存的数据在拷贝过程中不会被破坏,直接采用与memcpy相同的正向拷贝即可。 - 反向拷贝(高地址 -> 低地址) :当
dst > src且两者存在重叠时,源内存的后半部分与目标内存的前半部分重叠。此时如果正向拷贝,源数据会被立刻覆盖。因此,必须先将指针偏移到末尾,采用"倒着拷贝"的方式,确保在覆盖源数据之前,该数据已经被安全搬运到了目标位置。
四、总结与工程实践建议
memcpy与memmove是C语言操作内存的基石。在底层开发中,void*转char*的字节级操作是处理泛型数据的通用范式。在实际工程应用中,如果无法百分之百确定两块内存区域是否重叠,应无条件优先使用 **memmove**,以牺牲极微小的性能为代价,换取程序的绝对安全与稳定。此外,在编写此类底层函数时,务必使用assert对传入的指针进行非空校验,这是防御性编程的重要习惯。