Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> C++

เขียน memcpy() และ memmove() เองใน C++

ฟังก์ชัน memcpy()

memcpy() คัดลอกข้อมูลจาก source ไป destination จำนวน n ไบต์ ไม่จัดการ overlapping (หากทับกันพฤติกรรม undefined)

Prototype

void* memcpy(void* dest, const void* src, size_t n);

Implementation

#include <cstddef>  // size_t

void* myMemcpy(void* dest, const void* src, size_t n) {
    unsigned char* d = static_cast<unsigned char*>(dest);
    const unsigned char* s = static_cast<const unsigned char*>(src);
    
    for (size_t i = 0; i < n; i++) {
        d[i] = s[i];
    }
    return dest;
}

ฟังก์ชัน memmove()

memmove() คล้าย memcpy() แต่ จัดการ overlapping ได้อย่างถูกต้อง โดยคัดลอกผ่าน temporary buffer หรือคัดลอกย้อนกลับ

Prototype

void* memmove(void* dest, const void* src, size_t n);

Implementation (ใช้ Temporary Buffer)

void* myMemmove(void* dest, const void* src, size_t n) {
    if (dest == src || n == 0) return dest;
    
    unsigned char* d = static_cast<unsigned char*>(dest);
    const unsigned char* s = static_cast<const unsigned char*>(src);
    
    // จัดสรร temporary buffer
    unsigned char* temp = new unsigned char[n];
    
    // คัดลอก src -> temp
    for (size_t i = 0; i < n; i++) {
        temp[i] = s[i];
    }
    
    // คัดลอก temp -> dest
    for (size_t i = 0; i < n; i++) {
        d[i] = temp[i];
    }
    
    delete[] temp;
    return dest;
}

Implementation แบบไม่ใช้ Extra Memory (Optimized)

void* myMemmoveOpt(void* dest, const void* src, size_t n) {
    unsigned char* d = static_cast<unsigned char*>(dest);
    const unsigned char* s = static_cast<const unsigned char*>(src);
    
    if (d < s) {
        // src อยู่หน้า dest: คัดลอกไปข้างหน้า (forward) ปลอดภัย
        for (size_t i = 0; i < n; i++) {
            d[i] = s[i];
        }
    } else if (d > s) {
        // src อยู่หลัง dest: คัดลอกย้อนกลับ (backward) เพื่อไม่ทับข้อมูลที่ยังไม่อ่าน
        for (size_t i = n; i > 0; i--) {
            d[i - 1] = s[i - 1];
        }
    }
    // d == s: ไม่ต้องทำอะไร
    return dest;
}

ตัวอย่างการใช้งาน

#include <iostream>
#include <cstring>
using namespace std;

int main() {
    // memcpy example
    char src1[] = "Hello!";
    char dest1[100];
    myMemcpy(dest1, src1, strlen(src1) + 1);  // +1 สำหรับ null terminator
    cout << "Copied string: " << dest1 << endl;
    
    // memmove example - overlapping
    char buffer[] = "abcdefghijklmnop";
    cout << "Before memmove: " << buffer << endl;
    
    // คัดลอก "abcdef" (6 chars) จาก index 0 ไป index 5 (ทับกัน)
    myMemmoveOpt(buffer + 5, buffer, 6);
    cout << "After memmove:  " << buffer << endl;
    // ผลลัพธ์: "abcdeabcdefghijkl" (6 chars แรกถูกคัดลอกไปทับที่ index 5)
    
    return 0;
}

ผลลัพธ์

Copied string: Hello!
Before memmove: abcdefghijklmnop
After memmove:  abcdeabcdefghijkl

ความแตกต่างสำคัญ

ด้านmemcpymemmove
OverlappingUndefined BehaviorSafe (ถูกต้อง)
Performanceเร็วกว่า (ไม่ต้องเช็ค)ช้ากว่าเล็กน้อย
Use caseรู้แน่ว่าไม่ทับกันไม่แน่ใจหรือรู้ว่าทับกัน

สรุป

memcpy ใช้เมื่อแน่ใจว่า memory regions ไม่ทับกัน (เร็วกว่า) memmove ใช้เมื่ออาจทับกันหรือไม่แน่ใจ (ปลอดภัย) ใน C++ สมัยใหม่ ควรใช้ std::copy, std::copy_backward, หรือ std::memmove แทนเพื่อ type safety