`memcpy` 與 `memmove` 是記憶體塊複製的核心函數,唯一區別在於**重疊處理**。本文提供生產級實現,解析重疊判斷邏輯、向量化優化方向、嚴格別名規則合規性。
#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;
}
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] 讀到已污染資料
// 簡易字長級複製 (假設 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_t | 64 位系統大於 2GB 複製失效 | 嚴格使用 size_t |
`memcpy` = **極速、無重疊保證**;`memmove` = **安全、處理重疊、微小開銷**。核心判斷:**`dest` 是否落在 `[src, src+count)` 區間內**。現代開發**直接使用標準庫**,編譯器內建 + libc 優化 (向量化、非暫存寫入、預取) 遠超手寫。面試必會:重疊判斷邏輯、反向複製必要性、字長級優化思路、嚴格別名規則中 `char*` 的特權地位。