Spec-Zone.ru › C

memmove, memmove_s

Определено в заголовке <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 в случае отсутствия перекрытия.

Там, где строгое алиасирование запрещает проверку одной и той же памяти как значений двух разных типов, memmove может использоваться для преобразования значений.

Пример

#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <string.h>
#include <stdlib.h>
 
int main(void)
{
    char str[] = "1234567890";
    puts(str);
    memmove(str+4, str+3, 3); // copy from [4,5,6] to [5,6,7]
    puts(str);
 
    // setting effective type of allocated memory to be int
    int *p = malloc(3*sizeof(int));   // allocated memory has no effective type
    int arr[3] = {1,2,3};
    memmove(p,arr,3*sizeof(int));     // allocated memory now has an effective type
 
    // reinterpreting data
    double d = 0.1;
//    int64_t n = *(int64_t*)(&d); // strict aliasing violation
    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 is greater than 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

Ссылки

  • Стандарт 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

См. также

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

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/c/string/byte/memmove

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API