이번 글에서는 C 언어로 memcpy() 함수를 직접 구현하는 방법을 알아보겠습니다. memcpy()는 표준 라이브러리(string.h)에 포함된 함수로, 한 메모리 위치에서 다른 위치로 데이터 블록을 복사하는 역할을 합니다. 기본 문법은 다음과 같습니다.
void * memcpy(void *dest, const void *src, size_t num);
각 매개변수의 의미는 다음과 같습니다.
- dest: 데이터가 복사될 목적지 메모리 주소
- src: 복사할 데이터가 있는 원본 메모리 주소
- num: 복사할 바이트 수
구현 원리
자체 memcpy()를 만들려면 전달받은 src와 dest 주소를 char* 타입으로 형 변환한 후, 바이트 단위로 데이터를 하나씩 복사하면 됩니다. 이 방식이 가능한 이유는 char가 C 언어에서 가장 작은 주소 지정 단위(1바이트)이기 때문입니다. 어떤 자료형의 데이터든 char 포인터로 접근하면 메모리 내용을 바이트 단위로 읽고 쓸 수 있습니다.
아래 예제 코드를 통해 구체적인 구현 방법을 살펴보겠습니다.
예제 코드
#include<stdio.h>
#include<string.h>
void custom_memcpy(void *dest, void *src, size_t n) {
int i;
// src와 dest를 char*로 형 변환
char *src_char = (char *)src;
char *dest_char = (char *)dest;
for (i = 0; i < n; i++)
dest_char[i] = src_char[i]; // 바이트 단위로 복사
}
main() {
char src[] = "Hello World";
char dest[100];
custom_memcpy(dest, src, strlen(src)+1);
printf("복사된 문자열: %s\n", dest);
int arr[] = {10, 20, 30, 40, 50, 60, 70, 80, 90};
int n = sizeof(arr)/sizeof(arr[0]);
int dest_arr[n], i;
custom_memcpy(dest_arr, arr, sizeof(arr));
printf("복사된 배열: ");
for (i = 0; i < n; i++)
printf("%d ", dest_arr[i]);
}실행 결과
복사된 문자열: Hello World 복사된 배열: 10 20 30 40 50 60 70 80 90
코드 설명
위 예제에서는 두 가지 경우를 테스트했습니다. 첫 번째는 문자열 복사로, strlen(src)+1을 사용해 널 종료 문자('\0')까지 포함하여 복사합니다. 두 번째는 정수 배열 복사로, sizeof(arr)를 사용해 배열 전체 크기를 바이트 단위로 계산하여 복사합니다. 두 경우 모두 custom_memcpy()가 자료형에 관계없이 올바르게 동작하는 것을 확인할 수 있습니다.
주의 사항
실무에서 memcpy()를 사용하거나 직접 구현할 때는 몇 가지 유의해야 할 점이 있습니다.
1. 메모리 영역 겹침: 표준 memcpy()는 소스와 목적지 메모리 영역이 겹치는 경우(undefined behavior) 동작을 보장하지 않습니다. 겹치는 영역을 다뤄야 한다면 memmove()를 사용해야 합니다.
2. 버퍼 오버플로우: num 값이 목적지 버퍼 크기보다 크면 버퍼 오버플로우가 발생할 수 있으므로, 항상 목적지 버퍼의 크기를 충분히 확보해야 합니다.
3. 성능 최적화: 실제 표준 라이브러리의 memcpy()는 바이트 단위 대신 워드(word) 단위 복사나 SIMD 명령어 등을 활용해 훨씬 빠르게 최적화되어 있습니다. 위 구현은 학습용으로 이해하기 쉽게 작성된 기본적인 형태입니다.