Namespaces
Variants

memmove, memmove_s

From cppreference.net
< c ‎ | string ‎ | byte
헤더 파일에 정의됨 <string.h>
void * memmove ( void * dest, const void * src, size_t count ) ;
(1)
errno_t memmove_s ( void * dest, rsize_t destsz, const void * src, rsize_t count ) ;
(2) (C11 이후)
1) src 가 가리키는 객체로부터 dest 가 가리키는 객체로 count 개의 문자를 복사합니다. 두 객체 모두 unsigned char 배열로 해석됩니다. 객체들은 중첩될 수 있습니다: 문자가 임시 문자 배열로 복사된 후, 해당 배열에서 dest 로 문자가 복사되는 것처럼 동작합니다.
dest 배열의 끝을 넘어서 접근이 발생하면 동작은 정의되지 않습니다. dest 또는 src 가 유효하지 않거나 null 포인터인 경우에도 동작은 정의되지 않습니다.
2) (1) 과 동일하지만, 런타임에 다음 오류를 감지할 경우 전체 대상 범위 [ dest, dest + destsz ) 를 0으로 채우고( dest destsz 가 모두 유효한 경우) 현재 설치된 constraint handler 함수를 호출합니다:
  • dest 또는 src 가 null 포인터인 경우
  • destsz 또는 count RSIZE_MAX 보다 큰 경우
  • count destsz 보다 큰 경우 (버퍼 오버플로우가 발생할 경우)
dest 가 가리키는 문자 배열의 크기가 count < destsz 인 경우 동작은 정의되지 않습니다. 즉, destsz 의 잘못된 값은 임박한 버퍼 오버플로우를 노출하지 않습니다.
모든 경계 검사 함수와 마찬가지로, memmove_s 는 구현체가 __STDC_LIB_EXT1__ 를 정의하고, 사용자가 __STDC_WANT_LIB_EXT1__ 를 정수 상수 1 으로 정의한 후 <string.h> 를 포함할 경우에만 사용 가능함이 보장됩니다.

목차

매개변수

dest - 복사 대상 객체를 가리키는 포인터
destsz - 대상에서 수정할 최대 바이트 수 (일반적으로 대상 객체의 크기)
src - 복사 원본 객체를 가리키는 포인터
count - 복사할 바이트 수

반환값

1) dest 의 복사본을 반환합니다
2) 성공 시 0을 반환하고 오류 시 0이 아닌 값을 반환합니다. 또한 오류 발생 시, dest 가 null 포인터가 아니고 destsz 가 유효한 경우, destsz 개의 제로 바이트를 대상 배열에 기록합니다.

참고 사항

memmove 는 할당 함수로 얻은 객체의 effective type 을 설정하는 데 사용될 수 있습니다.

"임시 버퍼가 사용되는 것처럼" 지정되었지만, 이 함수의 실제 구현에서는 오버헤드나 이중 복사 또는 추가 메모리가 발생하지 않습니다. 일반적인 접근 방식(glibc 및 bsd libc)은 대상이 소스보다 앞서 시작하는 경우 버퍼의 시작부터 앞으로 바이트를 복사하고, 그렇지 않은 경우 끝에서 뒤로 복사하며, 겹침이 전혀 없는 경우에는 더 효율적인 memcpy 로 대체됩니다.

strict aliasing 이 서로 다른 두 타입의 값으로 동일한 메모리를 검사하는 것을 금지하는 경우, memmove 를 사용하여 값을 변환할 수 있습니다.

예제

#define __STDC_WANT_LIB_EXT1__ 1
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
    char str[] = "1234567890";
    puts(str);
    memmove(str + 4, str + 3, 3); // [4,5,6]에서 [5,6,7]로 복사
    puts(str);
    // 할당된 메모리의 유효 타입을 int로 설정
    int* p = malloc(3 * sizeof(int)); // 할당된 메모리는 유효 타입이 없음
    int arr[3] = {1, 2, 3};
    memmove(p, arr, 3 * sizeof(int)); // 할당된 메모리에는 이제 유효 타입이 있음
    // 데이터 재해석
    double d = 0.1;
    // int64_t n = *(int64_t*)(&d); // strict aliasing 위반
    int64_t n;
    memmove(&n, &d, sizeof d); // OK
    printf("%a is %" PRIx64 " as an int64_t\n", d, n);
#ifdef __STDC_LIB_EXT1__
    set_constraint_handler_s(ignore_handler_s);
    char src[] = "aaaaaaaaaa";
    char dst[] = "xyxyxyxyxy";
    int r = memmove_s(dst, sizeof dst, src, 5);
    printf("dst = \"%s\", r = %d\n", dst, r);
    r = memmove_s(dst, 5, src, 10); // count가 destsz보다 큼
    printf("dst = \"");
    for (size_t ndx = 0; ndx < sizeof dst; ++ndx)
    {
        char c = dst[ndx];
        c ? printf("%c", c) : printf("\\0");
    }
    printf("\", r = %d\n", r);
#endif
}

가능한 출력:

1234567890
1234456890
0x1.999999999999ap-4 is 3fb999999999999a as an int64_t
dst = "aaaaayxyxy", r = 0
dst = "\0\0\0\0\0yxyxy", r = 22

참조문헌

  • C23 표준 (ISO/IEC 9899:2024):
  • 7.24.2.2 The memmove function (p: TBD)
  • K.3.7.1.2 The memmove_s function (p: TBD)
  • C17 표준 (ISO/IEC 9899:2018):
  • 7.24.2.2 memmove 함수 (p: 264)
  • K.3.7.1.2 memmove_s 함수 (p: 446)
  • C11 표준 (ISO/IEC 9899:2011):
  • 7.24.2.2 The memmove function (p: 363)
  • K.3.7.1.2 The memmove_s function (p: 615)
  • C99 표준 (ISO/IEC 9899:1999):
  • 7.21.2.2 memmove 함수 (p: 326)
  • C89/C90 표준 (ISO/IEC 9899:1990):
  • 4.11.2.2 The memmove function

참고 항목

버퍼를 다른 버퍼로 복사
(함수)
두 배열(겹칠 수 있음) 사이에서 지정된 개수의 와이드 문자를 복사
(함수)