首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C語言記憶體操作函數模擬實現:memcpy 與 memmove 深度解析

     編輯:關於C語言

C語言記憶體操作函數模擬實現:memcpy 與 memmove 深度解析

`memcpy` 與 `memmove` 是記憶體塊複製的核心函數,唯一區別在於**重疊處理**。本文提供生產級實現,解析重疊判斷邏輯、向量化優化方向、嚴格別名規則合規性。

1. memcpy —— 不處理重疊,極致效能

#include <assert.h>
#include <stddef.h>  // size_t

void *my_memcpy(void *dest, const void *src, size_t count) {
    assert(dest && src);
    
    char *d = (char *)dest;
    const char *s = (const char *)src;
    char *ret = d;
    
    // 字節級複製 (基礎版)
    while (count--) {
        *d++ = *s++;
    }
    
    return ret;
}

關鍵特性

  • 行為未定義於重疊:呼叫者必須保證記憶體區塊不重疊
  • 無類型概念:純位元組複製,適用於任意型別
  • 返回 dest:支援鏈式調用
  • 嚴格別名規則:`char*` 可別名任意型別,合規訪問記憶體

2. memmove —— 安全處理重疊

void *my_memmove(void *dest, const void *src, size_t count) {
    assert(dest && src);
    
    char *d = (char *)dest;
    const char *s = (const char *)src;
    char *ret = d;
    
    if (d == s || count == 0) return ret;  // 快速路徑
    
    // 重疊判斷:dest 在 src 之後,且距離小於 count
    // 需從後向前複製,避免覆蓋未讀取的源資料
    if (d > s && d < s + count) {
        // 重疊:從尾部開始複製
        d += count;
        s += count;
        while (count--) {
            *--d = *--s;
        }
    } else {
        // 不重疊或 dest 在 src 之前:正向複製 (同 memcpy)
        while (count--) {
            *d++ = *s++;
        }
    }
    return ret;
}

重疊判斷邏輯圖解

情況 1:不重疊 (正向安全)
src: [======]
dest:           [======]
d > s + count → 正向複製 ✓

情況 2:dest 在 src 之前 (正向安全)
src:       [======]
dest: [======]
d < s → 正向複製 ✓ (src 資料先被讀取,再被 dest 覆蓋無影響)

情況 3:dest 在 src 之後且重疊 (必須反向)
src: [======]
dest:    [======]
d > s 且 d < s + count → 反向複製 ✓
// 正向會導致:先複製 src[0]→dest[0],覆蓋 src[2],後續讀取 src[2] 讀到已污染資料

效能優化:向量化複製 (生產級 libc 做法)

// 簡易字長級複製 (假設 size_t 為 8 位元組)
void *my_memcpy_fast(void *dest, const void *src, size_t count) {
    char *d = (char *)dest;
    const char *s = (const char *)src;
    
    // 1. 對齊處理:先複製字節直到 d 對齊到 sizeof(size_t)
    while (count && ((uintptr_t)d % sizeof(size_t))) {
        *d++ = *s++;
        count--;
    }
    
    // 2. 字長級批量複製
    size_t *wd = (size_t *)d;
    const size_t *ws = (const size_t *)s;
    while (count >= sizeof(size_t)) {
        *wd++ = *ws++;
        count -= sizeof(size_t);
    }
    
    // 3. 餘數字節複製
    d = (char *)wd;
    s = (const char *)ws;
    while (count--) *d++ = *s++;
    
    return dest;
}

編譯器內建優化

// 現代編譯器會自動識別並優化
void *my_memcpy_builtin(void *dest, const void *src, size_t n) {
    return __builtin_memcpy(dest, src, n);  // GCC/Clang 內建
    // 或直接呼叫 libc: return memcpy(dest, src, n);
}

常見面試陷阱

陷阱錯誤後果正確認知
memcpy 用於重疊區域資料損壞、無限迴圈、UB重疊必須用 memmove
反向複製條件寫錯漏判重疊或誤判非重疊`d > s && d < s + count`
忘記處理 count=0指標溢出、UB開頭 `if (!count) return dest;`
用 int 而非 size_t64 位系統大於 2GB 複製失效嚴格使用 size_t

總結

`memcpy` = **極速、無重疊保證**;`memmove` = **安全、處理重疊、微小開銷**。核心判斷:**`dest` 是否落在 `[src, src+count)` 區間內**。現代開發**直接使用標準庫**,編譯器內建 + libc 優化 (向量化、非暫存寫入、預取) 遠超手寫。面試必會:重疊判斷邏輯、反向複製必要性、字長級優化思路、嚴格別名規則中 `char*` 的特權地位。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved