Книга: Linux программирование в примерах
12.2.2. Копирование памяти: memcpy(), memmove() и memccpy()
12.2.2. Копирование памяти: memcpy()
, memmove()
и memccpy()
Три функции копируют один блок памяти в другой. Первые две функции отличаются в обработке перекрывающихся областей памяти; третья копирует память, но останавливается при встрече с определенным значением.
void *memcpy(void *dest, const void *src, size_t count)
Это простейшая функция. Она копирует count
байтов из src
в dest
. Она не обрабатывает перекрывающиеся области памяти. Функция возвращает dest
.
void *memmove(void *dest, const void *src, size_t count)
Подобно memcpy()
, она также копирует count
байтов из src
в dest
. Однако, она обрабатывает перекрывающиеся области памяти. Функция возвращает dest
.
void *memccpy(void *dest, const void *src, int val, size_t count)
Эта копирует байты из src
в dest
, останавливаясь либо после копирования val
в dest
, либо после копирования count
байтов. Если она находит val
, то возвращает указатель на положение в dest
сразу за val
. В противном случае возвращается NULL
.
Теперь, в чем проблема с перекрывающейся памятью? Рассмотрим рис. 12.1.
Рис. 12.1. Перекрывающиеся копии
Целью является скопировать четыре экземпляра struct xyz
от data[0]
до data[3]
в участок от data[3]
до data[6]
. Здесь проблемой является data[3]
, побайтовое копирование с перемещением в памяти из data[0]
затрет data[3]
до того, как он будет безопасно скопирован в data[6]
! (Может возникнуть также сценарий, когда копирование в памяти в обратном направлении разрушит перекрывающиеся данные.)
Функция memcpy()
была первоначальной функцией в System V API для копирования блоков памяти; ее поведение для перекрывающихся блоков памяти не была подробно определена тем или иным способом. Для стандарта С 1989 г. комитет почувствовал, что это отсутствие определенности является проблемой, поэтому они придумали memmove()
. Для обратной совместимости memcpy()
была оставлена, причем поведение для перекрывающейся памяти было специально отмечено как неопределенное, а в качестве процедуры, корректно разрешающей проблемные случаи, была предложена memmove()
.
Какую из них использовать в своем коде? Для библиотечной функции, которая не знает, какие области памяти ей передаются, следует использовать memmove()
. Таким способом вы гарантируете, что не будет проблем с перекрывающимися областями. Для кода приложения, который «знает», что две области не перекрываются, можно безопасно использовать memcpy()
.
Как для memcpy()
, так и для memmove()
(как и для strcpy()
) буфер назначения является первым аргументом, а источник — вторым. Чтобы запомнить это, обратите внимание на порядок, который тот же самый, как в операторе присваивания:
dest = src;
(Справочные страницы во многих системах не помогают, предлагая прототип в виде 'void *memcpy(void *buf1, void *buf2, size_t n)
' и полагаясь на то, что текст объяснит, что есть что. К счастью, справочная страница GNU/Linux использует более осмысленные имена.)
- 12.2.1. Заполнение памяти: memset()
- Резервное копирование базы данных InterBase
- Резервное копирование многофайловых баз данных
- Резервное копирование при работе InterBase в режиме 24x7
- 3.2.1.2. Начальное выделение памяти: malloc()
- 8.2.8. Копирование хэша в массив
- Неисправности оперативной памяти
- Как работает модуль оперативной памяти
- Описание типов модулей оперативной памяти
- Извлечение и установка модулей памяти
- Характеристики модулей памяти
- ПО для диагностики оперативной памяти