memcpy 함수의 manual은 다음과 같다!

#include <string.h>
void *memcpy(void *restrict dst, const void *restrict src, size_t n);
restrict 키워드는 Description 이야기하면서 설명하겠다!
memcpy 함수는 src가 가리키는 메모리 영역에서 dst가 가리키는 메모리 영역으로 n바이트를 복사한다.
src가 가리키는 영역과 dst가 가리키는 영역이 겹칠 때의 behavior는 undefined이다!
이게 무슨 이야기냐면 아래 코드를 보자.
#include <stdio.h>
#include <string.h>
int main(void)
{
int arr[5] = {0, 1, 2, 3, 4};
memcpy(arr + 2, arr, 12);
//memcpy는 바이트 단위로 복사하기에 정수 3개 복사하기에는 12바이트가 필요하다.
//정수를 3개만 복사하는 이유는 4개 이상을 복사하면 arr 영역을 벗어나 오버플로우가 발생하기 때문이다.
for (int i = 0; i < 5; i++)
printf("%d ", arr[i]);
return (0);
}
위 코드를 실행하면 어떤 결과가 나올 거 같나요????
혹시 0 1 0 1 2를 생각하고 계신가요??

맞습니다.
그런데 제 노트북에서의 실행 결과는 다음과 같습니다.

오잉 왜 0 1 0 1 0이 나오죠???
이 경우에는 이렇게 이해할 수 있습니다.
- arr[2]에 arr[0]인 0이 저장된다.
- arr[3]에 arr[1]인 1이 저장된다.
- arr[4]에 arr[2]인 0이 저장된다.
그래서 출력 결과가 0 1 0 1 0이 나오는겁니다.
왜 같은 코드인데 다른 결과가 나오는 걸까요???
그 이유는restrict 키워드에 있습니다. (물론 내부 구현 방식에 따른 복사 순서를 보장하지 않는 것 때문도 있습니다.)
restrict 키워드는 포인터가 가리키는 메모리 영역이 다른 포인터와 겹치지 않음을 컴파일러에게 보장한다.
이는 컴파일러가 최적화를 수행할 때 매우 중요한 정보이고 최적화 수준에 따라 프로그램의 동작이 달라질 수 있다.
어떤 방식으로 최적화하냐에 따라 복사 순서가 달라지고 이에 따라 중간 상태의 데이터 오염 문제를 발생시킬 수 있어 예측 불가능한 동작이 발생합니다.
그럼 이러한 문제는 어떻게 해결하는가???
Description에 작성되어 있다! Description 내용 설명으로 다시 돌아가겠다!
src의 영역과 dst의 영역이 겹친다면 memmove를 사용하자!(memmove는 다음 게시글에서 설명하겠다!)//배열 복사
int src[5] = {1, 2, 3, 4, 5};
int dst[5];
memcpy(dst, src, 5 * sizeof(int));
//구조체 복사
//구조체의 멤버를 하나씩 복사하는 대신, 전체 구조체를 한 번에 복사할 수 있다.
struct MyStruct {
int a;
float b;
} src, dst;
src.a = 1;
src.b = 3.14;
memcpy(&dst, &src, sizeof(struct MyStruct));
/* 네트워크 프로그래밍
* 송신 버퍼나 수신 버퍼에 데이터를 복사할 때 사용된다.
* 네트워크 패킥을 생성하거나 ㅓ리할 때, 패킷의 헤더와 데이터를 조합하는 데 유용하다.
*/
char packet[256];
char header[64];
char data[192];
memcpy(packet, header, 64);
memcpy(packet + 64, data, 192);
/* 파일 입출력
* 파일에서 읽은 데이터를 버퍼에 복사하거나, 버퍼의 데이터를 파일에 쓸 때 사용된다.
* 대용량 데이터 처리가 필요한 경우 유용하다.
*/
void *src = (void *)0x1000;
void *dst = (void *)0x2000;
memcpy(dst, src, 4096);
/* 시스템 프로그래밍
* 저수준 메모리 작업이 필요한 경우, 커널이나 드라이버 개발 시 사용된다.
* 직접 메모리 주소를 다룰 때 유용하다.
*/
void *src = (void *)0x1000;
void *dst = (void *)0x2000;
memcpy(dst, src, 4096);
memcpy 함수는 dst의 값을 반환한다.void *ft_memcpy(void *dst, const void *src, size_t n)
{
unsigned char *d;
const unsigned char *s;
//NULL 포인터 검사
//가독성을 위해 NULL 메크로를 쓰는 것이 좋다.
//NULL 메크로는 stdlib.h, stdio.h, string.h 등의 헤더 파일에 정의되어 있다.
if (dst == NULL && src == NULL)
return (NULL);
d = (unsigned char *) dst;
s = (const unsigned char *) src;
while (n > 0)
{
*d = *s;
d++;
s++;
n--;
}
return (dst);
}
위의 구현에서 while문을 아래와 같이 바꿀 수 있다.
while (n-- > 0)
*d++ = *s++;