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) Копирует count символов из объекта, на который указывает src , в объект, на который указывает dest . Оба объекта интерпретируются как массивы unsigned char . Объекты могут перекрываться: копирование происходит так, как если бы символы были скопированы во временный массив символов, а затем символы были скопированы из массива в dest .
Поведение не определено, если доступ происходит за пределами массива dest. Поведение не определено, если либо dest или src является недопустимым или нулевым указателем.
2) То же, что и (1) , за исключением того, что при обнаружении следующих ошибок во время выполнения, обнуляется весь целевой диапазон [ dest, dest + destsz ) (если оба dest и destsz являются валидными) и вызывается текущая установленная функция обработки ограничений :
  • dest или src является нулевым указателем
  • 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) Возвращает ноль при успехе и ненулевое значение при ошибке. Также при ошибке, если dest не является нулевым указателем и destsz является допустимым, записывает destsz нулевых байтов в целевой массив.

Примечания

memmove может использоваться для установки эффективного типа объекта, полученного с помощью функции выделения памяти.

Несмотря на то, что функция описана «как если бы» использовался временный буфер, реальные реализации этой функции не несут накладных расходов на двойное копирование или дополнительную память. Распространённый подход (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); // нарушение строгого алиасинга
    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); // количество больше чем 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 Функция memmove (стр.: TBD)
  • K.3.7.1.2 Функция memmove_s (стр.: TBD)
  • Стандарт C17 (ISO/IEC 9899:2018):
  • 7.24.2.2 Функция memmove (стр. 264)
  • K.3.7.1.2 Функция memmove_s (стр. 446)
  • Стандарт C11 (ISO/IEC 9899:2011):
  • 7.24.2.2 Функция memmove (стр. 363)
  • K.3.7.1.2 Функция memmove_s (стр. 615)
  • Стандарт C99 (ISO/IEC 9899:1999):
  • 7.21.2.2 Функция memmove (стр: 326)
  • Стандарт C89/C90 (ISO/IEC 9899:1990):
  • 4.11.2.2 Функция memmove

Смотрите также

копирует один буфер в другой
(функция)
копирует определённое количество широких символов между двумя, возможно перекрывающимися, массивами
(функция)
C++ documentation для memmove