[C]memccpy & memmove
memccpy함수는 메모리값을 원하는 크기안에서 원하는 문자까지 복사하는 함수입니다.
memmove함수는 메모리값을 원하는 크기만큼 복사하는 함수입니다.(주소가 겹칠때 유용)
1️⃣ 함수원형
< memccpy >
void *memccpy(void *dst, const void *src, int c, size_t size)
< memmove >
void *memmove(void *dst, const void *src, size_t size)
2️⃣ 헤더파일, 반환값
반환값:
조건 memccpy memmove 성공시(문자찾을시) 복사된 문자열 다음주소(dst) 복사된 문자열 시작주소(dst) 실패시(문자못찾을시) NULL포인터(0) dst, src모두 NULL포인터일 때 segmentation fault NULL포인터(0) dst, src둘중하나가 NULL포인터일 때 segmentation fault segmentation fault 헤더파일: <string.h>
3️⃣ 함수구현
< memccpy >
void *memccpy(void *dst, const void *src, int c, size_t size)
{
unsigned char *dp;
const unsigned char *sp;
dp = dst;
sp = src;
while (size-- > 0)
{
*dp = *sp;
if (*sp == (unsigned char)c)
return (dp + 1);
dp++;
sp++;
}
return (0);
}
<memmove>
void *memmove(void *dst, const void *src, size_t size)
{
const unsigned char *sp;
unsigned char *dp;
size_t i;
i = 0;
dp = dst;
sp = src;
if (dp == NULL && sp == NULL)
return (0);
if (dp > sp)
{
while (size-- > 0)
*(dp + size) = *(sp + size);
}
else
{
while (size-- > 0)
*dp++ = *sp++;
}
return (dst);
}
4️⃣ 특징 & 주의사항
< memccpy >
- 찾고자하는 문자를 못찾을시 0을 반환하지만 복사는 이뤄집니다.
- size값을 dst, src의 크기보다 작게 잡아줘야 합니다.(컴파일러에 따라 경고메시지출력)
- 되도록이면 1바이트크기의 자료형만 사용하는 것이 좋습니다.(아래 자세한 내용)
< memmove >
- 첫번째인자(dst), 두번째인자(src) 둘다 NULL포인터이면 예상과 달리 대부분의 컴파일러에서 경고메시지 없이 NULL포인터를 반환하면서 정상컴파일이 되었습니다.
- size값을 dst, src의 크기보다 작게 잡아줘야 합니다.(컴파일러에 따라 경고메시지출력)
5️⃣ 코드예시(특이케이스)
1. < memccpy에서 1byte크기가 아닌 자료형을 사용할 경우 >
#include <stdio.h>
#include <string.h>
int main(void)
{
int word1[20] = { 0, };
int temp[] = {4423, 2, 3, 65281, 4};
int *result
result = memccpy(word1, temp, 65281, sizeof(temp));
if (result == 0)
printf("ss\n");
for (int i = 0; i < 5; i++)
printf("%d ", word1[i]);
printf("\n");
}
/*---출력---*/
5 2 3 1 0
- 기대값:
4423 2 3 65281 0
- 출력값:
4423 2 3 1 0
- 원인: 문자(c)를 찾은 지점에서 문제가 생김
- 이유: memccpy함수는 찾을문자(int c)를 내부적으로 1byte의 메모리만 비교하여 찾습니다. (int)65281의 메모리를 리틀엔디언 기준으로 본다면 “01 ff 00 00”으로 되어있는데 앞의 1byte크기인 “01”부분만을 비교하여 찾게 되고 복사를 종료하게 됩니다.
- 해결 방안:
- 3번째인자의 값에 “0xff”를 입력하면 65281의 메모리에서 “01 ff”까지 복사되어 기대값처럼 출력이 됩니다.
- int자료형일 경우 0 ~ 255(1byte범위)안에서만 다루는 것이 좋습니다.
3번째 인자(c))가 0일경우 문제가 생길 확률이 큽니다.
<3번째 원소(65281)의 실제메모리>
리틀 엔디언 | 빅 엔디언 | |
---|---|---|
(int)257 | 01 ff 00 00 | 00 00 ff 01 |
4byte단위(int)로 | 앞에서 부터 스텍에 쌓임 | 뒤에서 부터 스텍에 쌓임 |
- 결론: 예상치 못한 결과를 방지하기 위해서는 memccpy의 인자들을 1byte크기의 자료형을 사용하는 것이 좋습니다. 굳이 int형을 다루고 싶다면 0 ~255의 범위안에서 사용하는 것이 좋습니다.(또한 3번째인자(c)는 0을 사용하지 않는다)