- memcpy
-
memcpy (от англ. memory copy — копирование памяти) — функция стандартной библиотеки языка программирования Cи, копирующая содержимое одной области памяти в другую.
Функция определена в заголовочном файле string.h (а также в mem.h), описывается в стандартах ANSI C и POSIX.
Содержание
memcpy_s
В целях избежания лишних действий функция memcpy() не проверяет соответствие размера выходного буфера количеству копируемых байт, возлагая эту обязанность на программиста. В результате совершается достаточно много ошибок, способных привести к переполнению буфера.
Поэтому ближе к концу 2009 г. компания Microsoft добавила memcpy(), CopyMemory() и RtlCopyMemory() в список функций, запрещённых в соответствии с методикой разработки безопасных программ Secure Development Lifecycle (SDL). Те разработчики, которые хотят создавать совместимые с SDL приложения, должны будут использовать вместо memcpy() функцию memcpy_s, позволяющую указывать размер буфера. Функция memcpy_s() непереносима и не включена в стандарт Си.
Определение
void *memcpy(void *dst, const void *src, size_t n);
где:
- dst — адрес буфера назначения
- srс — адрес источника
- n — количество байт для копирования
Функция копирует n байт из области памяти, на которую указывает src, в область памяти, на которую указывает dst. Функция возвращает адрес назначения dst.
Области памяти не должны перекрываться
, иначе данные могут быть скопированы неправильно, например таким образом:
__src___ | | 1234567890xxxxx |__ ___| dst
после копирования буфер dst содержит данные отличные от исходных, так как они были разрушены в процессе копирования:
__dst___ | | 121212121212xxx
Что получится на самом деле, зависит от реализации функции (пример относится к одной из реализации приведенных ниже).
Для правильного копирования перекрывающихся областей нужно использовать функцию memmove(). Некоторые реализации memcpy() (например в libc FreeBSD и OpenBSD) делают то же что и memmove(), принуждая работать правильно даже неправильно написанную программу, однако при написании переносимой программы на это надеяться нельзя.
Алгоритм работы и реализации
memcpy() копирует содержимое src в буфер dst, например, так:
int i; for( i = 0; i < n; i++ ) ((unsigned char*)dst)[i] = ((unsigned char*)src)[i]; return dst;
Но данный пример будет работать медленнее чем любая практическая реализация, по причине того что они оптимизированы:
- не используют индексы, как в примере
- перемещают за один цикл не один байт, а блок равный машинному слову (2, 4 или 8 байт; 16, 32 или 64 бит), которое копируется процессором за то же время, что и байт. Такой подход наиболее эффективен при копировании данных, выровненных на границу машинного слова
- иногда используют инструкции процессора для работы с блоками данных (movsX для i386) в этом случае функция пишется с применением языка ассемблера
Пример частично оптимизированной версии:
int i, m; unsigned long *wdst = dst; // текущая позиция в буфере назначения unsigned long *wsrc = src; // текущая позиция в источнике unsigned char *cdst, *csrc; for(i = 0, m = n / sizeof(long); i < m; i++) // копируем основную часть блоками по 4 или 8 байт *(wdst++) = *(wsrc++); // (в зависимости от платформы) cdst = (unsigned char*)wdst; csrc = (unsigned char*)wsrc; for(i = 0, m = n % sizeof(long); i < m; i++) // остаток копируем побайтно *(cdst++) = *(csrc++); return dst;
Данная версия копирует 4 или 8 байт (размер типа long равен 32 битам на 32-битной платформе и 64 на 64-битной) за цикл, но не проверяет выравненности данных.
Пример использования
#include <string.h> unsigned int array[512]; // источник unsigned char byte_array[sizeof(array)]; // буфер назначения memcpy(byte_array, array, sizeof(array));
Ссылки
- Описание функции memcpy() в стандарте POSIX (англ.)
- Описание функции memcpy в составе Visual C++ (англ.)
- Сравнение скорости работы memcpy и цикла на C (англ.)
- Патч в ядре Linux, оптимизирующий memcpy (англ.)
См. также
Категория:- String.h
Wikimedia Foundation. 2010.