memove和memcpy源码实现

本文详细解析了C语言中memcpy和memmove函数的工作原理及使用场景。针对内存复制时源和目的地址是否重叠的情况,提供了不同的实现方式,确保数据正确高效地复制。
void* memcpy(void* dest, void* source, size_t count)
{
          void* ret = dest;
          //copy from lower address to higher address
          while (count--)
                  *dest++ = *source++;
           return ret;
}

 
void* memmove(void* dest, void* source, size_t count)
{

       void* ret = dest;
       if (dest <= source || dest >= (source + count))
       {
          //Non-Overlapping Buffers
          //copy from lower addresses to higher addresses
         while (count --)
               *dest++ = *source++;
       }
       else
       {

        //Overlapping Buffers
        //copy from higher addresses to lower addresses 内存重叠的情况
         dest += count - 1;
         source += count - 1;
         while (count--)
                *dest-- = *source--;
        }
        return ret;
}

`memcpy` 是C标准库中用于内存拷贝的函数,其源码实现需考虑**高效性****正确性**(如处理内存重叠)。以下是典型实现(基于glibc的简化版本)及关键点分析: --- ### **1. 经典 `memcpy` 实现(C语言)** ```c #include <stddef.h> // for size_t void *memcpy(void *dest, const void *src, size_t n) { if (dest == NULL || src == NULL || n == 0) { return dest; // 处理空指针或零长度 } char *d = dest; // 目标地址(按字节操作) const char *s = src; // 源地址(按字节操作) // 处理内存重叠(非标准行为,但避免潜在问题) if (d > s && d < s + n) { // 从后向前拷贝(避免覆盖未读取的数据) for (size_t i = n; i > 0; i--) { d[i-1] = s[i-1]; } } else { // 从前向后拷贝(正常情况) for (size_t i = 0; i < n; i++) { d[i] = s[i]; } } return dest; } ``` --- ### **2. 优化版本(按字长拷贝)** 现代实现通常按**机器字长**(如4/8字节)拷贝以提高效率: ```c void *memcpy(void *dest, const void *src, size_t n) { if (dest == NULL || src == NULL || n == 0) { return dest; } // 按字长拷贝(假设size_t为8字节) size_t *d_word = dest; const size_t *s_word = src; size_t align = n / sizeof(size_t); // 完整字长的数量 // 处理对齐部分(避免未对齐访问导致性能下降) if ((uintptr_t)dest % sizeof(size_t) == 0 && (uintptr_t)src % sizeof(size_t) == 0) { for (size_t i = 0; i < align; i++) { d_word[i] = s_word[i]; } } else { // 未对齐时逐字节拷贝 char *d_byte = dest; const char *s_byte = src; for (size_t i = 0; i < n; i++) { d_byte[i] = s_byte[i]; } return dest; } // 处理剩余字节 char *d_tail = (char *)dest + align * sizeof(size_t); const char *s_tail = (const char *)src + align * sizeof(size_t); size_t remainder = n % sizeof(size_t); for (size_t i = 0; i < remainder; i++) { d_tail[i] = s_tail[i]; } return dest; } ``` --- ### **3. 关键优化技术** #### **(1) 按字长拷贝** - 现代CPU一次可处理4/8字节(`size_t`),按字长拷贝比逐字节效率更高。 - **注意**:需确保源目标地址对齐(否则可能触发总线错误)。 #### **(2) 内存重叠处理** - **C标准**:`memcpy` 不要求处理重叠内存(行为未定义),但实际实现可能通过反向拷贝避免问题。 - **替代函数**:`memmove` 会显式处理重叠(如 `glibc` 的 `memcpy` 在检测到重叠时会调用 `memmove`)。 #### **(3) 向量化指令(SIMD)** - 现代编译器(如GCC)可能用SSE/AVX指令优化: ```c // GCC自动向量化示例(需开启-O3) for (size_t i = 0; i < n; i++) { ((char *)dest)[i] = ((const char *)src)[i]; } ``` --- ### **4. 边界条件处理** - **空指针**:直接返回(避免解引用NULL)。 - **零长度**:直接返回目标地址。 - **对齐问题**:未对齐时回退到逐字节拷贝。 --- ### **5. 实际库实现参考** #### **(1) glibc 的 `memcpy`** - 结合多种优化: - 小内存(<16字节)用逐字节拷贝。 - 大内存用字长拷贝+SIMD指令。 - 动态检测CPU特性(如AVX2)。 #### **(2) LLVM libc 的 `memcpy`** - 使用内联汇编优化特定架构(如x86_64的 `rep movsb`)。 --- ### **6. 测试代码示例** ```c #include <stdio.h> #include <string.h> int main() { char src[] = "Hello, memcpy!"; char dest[20]; memcpy(dest, src, strlen(src) + 1); // 拷贝字符串(包括'\0') printf("Copied: %s\n", dest); // 测试内存重叠(非标准用法,但某些实现支持) char buffer[] = "1234567890"; memcpy(buffer + 2, buffer, 5); // 从buffer[0]拷贝5字节到buffer[2] printf("Overlapped: %s\n", buffer); // 输出"1212345890"(行为依赖实现) return 0; } ``` --- ### **7. 扩展问题** 1. `memcpy` `memmove` 的核心区别是什么? 2. 如何手动优化 `memcpy` 以适应特定硬件(如ARM NEON)? 3. 为什么 `memcpy` 的实现通常不检查内存重叠? 4. 在嵌入式系统中,如何实现一个极简的 `memcpy`? 5. 如何通过汇编指令(如 `rep movsb`)优化 `memcpy`? ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值