memcpy 與 memmove 皆用於記憶體區塊複製,關鍵差異在於**記憶體區塊重疊時的行為**。本文透過原始碼分析,釐清兩者適用場景與效能考量。
void *memcpy(void *dest, const void *src, size_t n);
void *memmove(void *dest, const void *src, size_t n);
void *memcpy(void *dest, const void *src, size_t n) {
char *d = (char*)dest;
const char *s = (const char*)src;
while (n--) *d++ = *s++; // 單向正向複製
return dest;
}
若 src 區塊位於 dest 區塊之前且重疊,正向複製會覆寫尚未讀取的來源資料,導致資料損毀。
void *memmove(void *dest, const void *src, size_t n) {
char *d = (char*)dest;
const char *s = (const char*)src;
if (d <= s || d >= s + n) {
// 情況 1:無重疊 或 dest 在 src 之前(不重疊區域)
// 正向複製安全
while (n--) *d++ = *s++;
} else {
// 情況 2:dest 在 src 之後且重疊
// 必須反向複製,避免覆寫來源
d += n - 1;
s += n - 1;
while (n--) *d-- = *s--;
}
return dest;
}
兩區塊 不重疊 條件:
dest <= src || dest >= src + n
反之則重疊,必須使用 memmove。
| 場景 | memcpy | memmove |
|---|---|---|
| 無重疊 | 最快(單純正向複製,編譯器常優化為 SIMD 指令) | 略慢(需執行重疊判斷分支) |
| 重疊(dest < src) | **錯誤結果** | 正確(正向複製) |
| 重疊(dest > src) | **錯誤結果** | 正確(反向複製) |
memcpy(效能最佳,編譯器積極優化)。memmove(安全正確)。dst = src 或 std::copy(型別安全、編譯器優化)。std::copy、std::move、vector::assign 等演算法,避免裸指標操作。memcpy 以高度優化的組合語言實作(AVX2、NEON、SSE2),大塊複製效能極高。memmove 通常在判斷重疊後,同樣呼叫優化的複製核心。std::memcpy、std::memmove 位於 <cstring>。#include <cstring>
#include <iostream>
int main() {
char buf[20] = "ABCDEFGHIJ";
std::cout << "原始: " << buf << '\n';
// 重疊複製:將前 5 字元複製到位置 3 起始
// 預期結果: "ABCABCDEFG" (memmove) vs 損毀 (memcpy)
std::memmove(buf + 3, buf, 5);
std::cout << "memmove: " << buf << '\n';
std::strcpy(buf, "ABCDEFGHIJ");
std::memcpy(buf + 3, buf, 5); // 未定義行為
std::cout << "memcpy: " << buf << " (結果不可預期)" << '\n';
}