표준 라이브러리(string.h)의 memcpy 함수는 메모리 영역을 한 바이트씩 복사하는 데 사용됩니다. 이것은 배열, 구조체 및 기타 데이터 블록을 복사할 때 성능이 중요하고 형 변환이 필요하지 않은 범용 도구입니다.
문제의 역사:
memcpy는 첫 번째 표준 라이브러리 구현과 함께 등장했으며, "원시" 메모리 블록을 처리할 필요성이 있었기 때문에 생겨났습니다. 예를 들어 파일 작업, 네트워크 패킷 및 데이터 직렬화를 위한 것입니다. 유사한 함수는 거의 모든 저수준 언어에 존재합니다.
문제:
memcpy는 바이트로만 작동하며 데이터 유형, 정렬 또는 메모리 영역의 겹침에 대해 신경 쓰지 않습니다. 크기 또는 잘못된 영역 지정을 오류가 발생하면 메모리 손상 또는 예기치 않은 결과가 발생할 수 있습니다. 또한, 겹치는 영역에 대해 memcpy를 사용할 경우 정의되지 않은 동작이 발생합니다.
해결책:
아래와 같은 경우에만 memcpy를 사용하십시오:
memmove 함수를 사용하십시오.코드 예:
#include <string.h> typedef struct { int id; float value; } Item; Item src = {42, 3.14f}; Item dest; memcpy(&dest, &src, sizeof(Item)); // 구조체를 바이트 단위로 복사합니다.
주요 특징:
strlen을 복사하기 위해 memcpy를 사용할 수 있나요?
가능하지만 길이를 정확히 아는 경우에만 가능합니다. 만약 문자열이 null-terminated이면, strcpy 또는 strncpy를 사용하는 것이 일반적입니다. 크기를 혼동하면 메모리 초과 또는 null 종료문자가 손실될 수 있습니다.
char src[] = "abc"; char dest[4]; memcpy(dest, src, 4); // 3 문자 + '\0'이 복사됩니다.
비표준 정렬이나 포인터를 가진 구조체를 memcpy로 복사하면 어떻게 되나요?
memcpy는 의미론이나 내부 포인터를 고려하지 않습니다. 구조체가 동적 필드(char *buf;와 같은)를 저장하는 경우, 주소만 복사되고 해당 주소의 내용은 복사되지 않습니다. 이는 이른바 "표면 복사"를 초래합니다.
typedef struct { char *buf; } Wrapper; Wrapper src = {malloc(10)}; Wrapper dest; memcpy(&dest, &src, sizeof(Wrapper)); // 포인터 필드만 복사되고 내용은 복사되지 않습니다.
memcpy에서 src와 dest가 겹치는 경우에는 어떻게 되나요?
표준에 의해 정의되지 않은 동작이 발생할 수 있으며 데이터 손실이 발생할 수 있습니다. 겹치는 복사를 하려면 memmove를 사용하십시오:
memmove(dest, src, size); // 정확한 복사를 보장합니다.
배열이 겹칠 때: memcpy를 사용하여 배열의 일부를 오른쪽으로 이동하는 경우, src와 dest가 부분적으로 겹칩니다.
장점:
단점:
겹치는 영역 처리를 위해 memmove를 사용하는 경우로, 데이터 양이 원본 구조체의 바이트 수로 정확하게 계산됩니다.
장점:
단점:
memcpy에 비해 성능이 약간 낮습니다.