티스토리 뷰

IT/C, C++

_[C/C++] 동일한 메모리 위치에 메모리 데이터 복사하기 (memmove_s)

주인장 진빼이

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;
}

stu2.name 값이 James에서 JJoy로 변경되었다..

 

 

예제에서 사용되는 메모리 복사 호출 함수 코드이다.

이 코드가 작동됨으로서 기존 변수들이 가지고 있는 메모리 데이터의 변화를 그림으로 볼 것이다.

 

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 변수의 메모리 블럭 및 메모리 데이터.

 

 

 

stu1.name 주소에서 8Byte만큼 복사 대상 위치에 복사하는 것이다.

중요한건, 복사할 메모리 블럭의 크기는 복사 대상 버퍼 크기를 초과할 수 없다.

중간 버퍼가 없으므로 복사 진행 중에 값이 바뀐다면 바뀌는 값이 복사될 수 있다.

stu2 변수의 메모리 구조이다.

 

 

 

마지막으로 메모리 복사가 이루어지면 stu2 메모리 블럭 및 메모리 데이터는 다음과 같이 변경될 것이다.

메모리 복사가 진행된 후, stu2 메모리 구조이다.

 

노란색으로 칠한 부분이 복사가 진행되어 메모리 데이터가 변경되었다고 볼 수 있다.

만약 "Joy" 가 아니라 "Johnson" 을 복사하려고 했다면 성공했을까 ?

> 당연히 실패할 수 밖에 없다, 복사 대상 버퍼 크기(12Byte)보다 복사할 메모리 블럭의 크기(14Byte)가 크기 때문이다.

 

메모리 복사가 진행된 후 stu2.name 변수 값을 출력하면 " JJoy "가 출력되는 것을 눈으로 볼 수 있다.

 

예제는 매우 간단한 코드로 구성되어 있으니 여러 가지 상황을 만들어서 

직접 실습을 통해 연습하기 바란다.

 

메모리 복사는 어렵지 않고 재밌는 것이다.

댓글
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함