[libft] ft_memcpy
memcpy?
#include <string.h>
void *memcpy(void *dst, const void *src, size_t n);
Linux manpage description
: The memcpy() function copies n bytes from memory area src to memory area dst. The memory areas must not overlap. Use memmove(3) if the memory areas do overlap.
해석 및 부연설명
: src에 저장되어있는 값을 n만큼 복사해 dst의 시작주소부터 붙여넣은 후 그 주소를 반환한다. 각 메모리가 overlap되어있어서는 안되며, 그럴 경우엔 memcpy
대신 memmove
를 사용해야한다.
ex)
char dst[] = "abcdefghijklmnop";
char src[] = "12345";
memcpy(dst, src, sizeof(src) - 1);
printf("%s\n", dst);
코드 실행 결과
12345fghijklmnop
복사할 src의 맨 마지막에 있을 NUL을 고려하여 size를 설정해야한다.
의문점 및 생각해볼점
overlap이란
알기쉽게 정리되어있는 링크
두 변수의 메모리주소가 겹칠 경우 복사 및 붙여넣기시에 덮어씌워지는 현상이 문제가 되는 모양이다. 예를들어
dst O O O O 1 2 3 4 5 6 7 8
src a b c d 1 2 3 O O O O O
이런식으로 존재할경우 src의 값을 dst에 하나씩 복붙하다보면
dst O O O O a b c 4 5 6 7 8
src a b c d a b c O O O O O
이런식으로 아직 복사되지 않은 src의 뒷부분의 값이 원본 src와 달라지게 되어 최종적으로
dst O O O O a b c d a b c 8
src a b c d a b c O O O O O
라는 엉뚱한 결과가 나오게 될 것이다. 그러니까 memcpy
함수에서는 이런 문제가 생길 경우 핸들링할 수 없으니 memmove
라는 다른 함수를 써서 처리하라고 한다.
dst의 크기보다 더 큰 값을 복붙할경우
그냥 dst의 크기에 관계없이 복붙하겠다는 메모리 그대로 dst에 넣어버려 에러 혹은 엉뚱한 결과가 발생했다.
memset
함수 자체에서도 이를 따로 핸들링하지 않았으니 구현시에도 따로 뭔가 해줄 필요는 없을 것 같다.
- 비슷한 케이스들을 slack에서 검색해보다가 느낀건데,
NULL
포인터를 입력받았을시 원 함수에 특별한 처리사항이 없는 한 protect를 하느냐(NULL
반환), 마느냐(segfault 에러 등)는 사람에 따라 생각이 다를 수 있는 것 같다. 원하지 않는 입력이 들어왔을 때 에러가 발생해 프로그램이 종료되느냐 혹은 프로그램은 꺼지지 않게 하느냐 둘중 취향에 맞는 쪽으로 하는걸로. 난 전자가 나은 것 같다.
strcpy
와의 차이점
strcpy
는 애초에 문자열 끝 NULL문자가 나올때까지 복붙하고, memcpy
는 복붙할 byte 수를 지정하는 점부터 다르니 비교 대상을 strncpy
로 잡는게 더 적절해보인다.
strncpy와 memcpy의 차이점 링크
둘 다 거의 똑같다고 볼 수 있지만 결과적으로 strncpy
는 memcpy
와 달리 복사하는 src의 NULL
이 언제나오는지를 계속 체크한다는 점이 달랐다.
n만큼 복사하는 도중에 NULL
이 나오면 strncpy
는 거기서 끝이고, memcpy
는 NULL
과 상관없이 딱 정해진 n만큼을 무조건 복사한다.
그래서 NULL
을 꾸준히 확인하는 strncpy
보다 memcpy
가 좀 더 빠르다고 한다.
형변환은 어디에서?
(unsigned char)*ptr
포인터 ptr을 타입에 따른 메모리만큼 읽은 후, 그 값을unsigned char
형으로 형변환한다.*(unsigned char *)ptr
포인터 ptr을unsigned char *
형으로 바꾼 후unsigned char *
형에 해당하는 메모리를 읽어 그 값을 구한다.
ft_memcpy 구현
void *ft_memcpy(void *dst, const void *src, size_t size)
{
void *result;
result = dst;
if (dst == src)
return (result);
while (size-- > 0)
*(unsigned char *)dst++ = *(unsigned char *)src++;
return (result);
}
dst나 src 한쪽만 NULL
인 경우는 segmentation fault
가 발생하여서 따로 protect 하지 않을 생각이었으나, dst와 src가 둘다 NULL
로 입력될경우 원 함수인 memset
에서는 NULL
포인터를 반환하였다.
따라서 dst == src 조건을 부여해 memset
함수와 동일하게 작동되도록 구현하였다.