티스토리 뷰
TIP
memmove() 함수와 다르게 overflow safe 이슈가 존재하지 않습니다. (memmove_s() 함수는 안전합니다)
서론
memcpy() 함수를 호출하여 메모리 데이터를 복사할 수 있다.
하지만 동일한 메모리 데이터를 복사하기 위해서는 memmove_s() 함수를 이용해야 한다.
memmove_s() 함수에 대해 하나씩 살펴보자.
prototype
함수 prototype을 보면 MBCS, WBCS별로 사용하는 함수가 다르다.
하지만 memmove_s() 함수 하나로도 WBCS 문자열 데이터도 복사할 수 있다. (자세한건 예제를 참고하자)
errno_t memmove_s(
void *dest,
size_t numberOfElements,
const void *src,
size_t count
);
errno_t wmemmove_s(
wchar_t *dest,
size_t numberOfElements,
const wchar_t *src,
size_t count
);
메모리 블록과 메모리 데이터
매개변수와 반환값
memcpy_s() 함수와 비슷하다. 버퍼 간 메모리 데이터를 안전하게 복사한다.
하지만 중간에 버퍼가 하나 더 있어 복사를 진행한 뒤, 복사 대상 버퍼에 복사하게 된다.
중간에 버퍼가 있기 때문에 복사할 버퍼와 복사 대상 버퍼가 겹치더라도 안전하게 복사할 수 있다.
memmove_s() 함수를 호출할 때 필요한 매개변수와 반환 값은 다음과 같다.
매개변수 목록 | 설명 |
void* dest | destination 줄임말, 복사 대상 버퍼 |
size_t destSize | 복사 대상 버퍼 크기 |
const void *src | source 줄임말, 복사할 값을 가지고 있는 버퍼 |
size_t count | 복사할 바이트 수 |
필요한 헤더 - ANSI: string.h / UNICODE: wchar.h | |
> destSize가 명시되어 있어 오버플로우 이슈가 발생하지 않습니다. |
source가 가르키는 곳에 count 크기의 메모리 데이터를 dest가 가리키는 곳에 중간 버퍼를 거쳐 복사하는 것이다.
(단, 대상 버퍼 크기(destSize)는 복사할 바이트 수(count)보다 작을 수 없음)
함수의 반환값은 메모리 복사가 성공적으로 이루어지면 0을 반환, 이외 errno_t 타입의 에러코드가 반환된다.
예제: wchar_t 문자열 멤버 변수 메모리 데이터 복사하기
다음은 stu1.name 변수의 메모리 데이터("Joy")를 stu.name[1] 주소에서 복사한 크기만큼 복사하는 예제이다.
#include "pch.h"
#include <iostream>
#include <tchar.h>
class student {
public:
wchar_t name[6];
int id;
void showData()
{
std::wcout << "name: " << name << ", " << "id: " << id << "\n";
}
};
int main()
{
student stu1 = { L"Joy", 40 };
std::cout << "stu1: ";
stu1.showData();
student stu2 = { L"James", 80 };
memcpy_s(&stu2.name[1], sizeof(stu2.name), stu1.name, (wcslen(stu1.name) * 2) + 2);
std::cout << "stu2: ";
stu2.showData();
return 0;
}
예제에서 사용되는 메모리 복사 호출 함수 코드이다.
이 코드가 작동됨으로서 기존 변수들이 가지고 있는 메모리 데이터의 변화를 그림으로 볼 것이다.
wcslen에서 *2를 하는 이유는 memcpy_s는 byte를 기준으로 하기 때문이다.
WBCS는 문자를 표현하는데 2byte를 사용된다.
마지막에 +2를 한 이유는 NULL 값을 포함시켜서 복사하기 위해서이다.
memcpy_s(&stu2.name[1], sizeof(stu2.name), stu1.name, (wcslen(stu1.name) * 2) + 2);
아래 그림에서 stu1 변수의 메모리 블럭 및 메모리 데이터를 볼 수 있다.
stu1.name 주소에서 8Byte만큼 복사 대상 위치에 복사하는 것이다.
중요한건, 복사할 메모리 블럭의 크기는 복사 대상 버퍼 크기를 초과할 수 없다.
중간 버퍼가 없으므로 복사 진행 중에 값이 바뀐다면 바뀌는 값이 복사될 수 있다.
마지막으로 메모리 복사가 이루어지면 stu2 메모리 블럭 및 메모리 데이터는 다음과 같이 변경될 것이다.
노란색으로 칠한 부분이 복사가 진행되어 메모리 데이터가 변경되었다고 볼 수 있다.
만약 "Joy" 가 아니라 "Johnson" 을 복사하려고 했다면 성공했을까 ?
> 당연히 실패할 수 밖에 없다, 복사 대상 버퍼 크기(12Byte)보다 복사할 메모리 블럭의 크기(14Byte)가 크기 때문이다.
메모리 복사가 진행된 후 stu2.name 변수 값을 출력하면 " JJoy "가 출력되는 것을 눈으로 볼 수 있다.
예제는 매우 간단한 코드로 구성되어 있으니 여러 가지 상황을 만들어서
직접 실습을 통해 연습하기 바란다.
메모리 복사는 어렵지 않고 재밌는 것이다.