Computer >> 컴퓨터 >  >> 프로그래밍 >> C++

C++로 memcpy()와 memmove() 함수 직접 구현하기


memcpy() 함수는 원본(source) 위치에서 대상(destination) 위치로 데이터를 복사하는 C/C++ 표준 라이브러리의 내장 함수입니다. 문자열뿐 아니라 배열, 구조체 등 어떤 종류의 메모리 블록이든 바이트 단위로 복사할 수 있습니다.

memcpy 함수의 프로토타입은 다음과 같습니다.

void * memcpy(void *destination_location, void *source_location, size_t size)

  • destination_location: 데이터가 복사될 대상 메모리의 주소
  • source_location: 복사할 데이터가 저장된 원본 메모리의 주소
  • size: 복사할 데이터의 크기(바이트 단위)

구현 아이디어는 간단합니다. 원본과 대상 포인터를 char * 타입으로 변환한 뒤, 지정된 크기만큼 한 바이트씩 순서대로 복사하면 됩니다. 호출 시에는 인자 순서가 (대상, 원본, 크기)임에 유의해야 합니다.

예제: memcpy() 구현

#include<stdio.h>
#include<string.h>
void MemcpyFunc(void *dest, void *src, size_t n){
    char *dataS = (char *)src;
    char *dataD = (char *)dest;
    for (int i=0; i<n; i++)
       dataD[i] = dataS[i];
}
int main() {
    char dataS[] = "Hello!";
    char dataD[100];
    MemcpyFunc(dataD, dataS, strlen(dataS)+1);
    printf("Copied string is %s", dataD);
    return 0;
}

출력 결과

Copied string is Hello!

memmove() 함수 역시 memcpy()처럼 원본에서 대상으로 데이터를 한 바이트씩 복사하지만, memcpy()가 가진 한 가지 문제를 보완한 함수입니다. memcpy()는 원본과 대상의 메모리 영역이 서로 겹치는 경우 올바른 결과를 보장하지 못합니다.

memmove()는 이런 겹침(overlap) 문제를 해결하기 위해 임시 버퍼를 활용합니다. 먼저 원본 데이터 전체를 임시 배열에 복사한 뒤, 다시 임시 배열에서 대상으로 복사하는 두 단계 방식을 사용합니다. 덕분에 원본과 대상이 겹쳐 있어도 안전하게 데이터를 이동할 수 있습니다.

예제: memmove() 구현

#include<stdio.h>
#include<string.h>
void MemmoveFunc(void *dest, void *src, size_t n){
    char *dataS = (char *)src;
    char *dataD = (char *)dest;
    char *temp = new char[n];
    for (int i=0; i<n; i++)
       temp[i] = dataS[i];
    for (int i=0; i<n; i++)
       dataD[i] = temp[i];
    delete[] temp;
}
int main() {
    char dataS[] = "Hello!";
    char dataD[100];
    MemmoveFunc(dataD, dataS, strlen(dataS)+1);
    printf("Moved string is %s", dataD);
    return 0;
}

출력 결과

Moved string is Hello!

memcpy()와 memmove()의 차이점

  • memcpy(): 복사 속도가 빠르지만, 원본과 대상 메모리가 겹치면 동작이 보장되지 않습니다.
  • memmove(): 임시 버퍼를 거치므로 약간 느릴 수 있지만, 메모리가 겹치는 상황에서도 항상 안전하게 동작합니다.

따라서 두 메모리 영역이 절대 겹치지 않는 것이 확실하다면 memcpy()를, 겹침 가능성이 조금이라도 있다면 반드시 memmove()를 사용하는 것이 좋습니다.