memcpy (от англ. memory copy — копирование памяти) — функция стандартной библиотеки языка программирования Си, копирующая содержимое одной области памяти в другую.
Функция определена в заголовочном файле string.h (а также в mem.h), описывается в стандартах ANSI C и POSIX.
Чтобы не выполнять лишних действий, функция 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);
где:
Функция копирует 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;
Но данный пример будет работать медленнее, чем любые практические реализации, так как они оптимизированы:
Пример частично оптимизированной версии:
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) / sizeof(unsigned int)]; // буфер назначения
memcpy(byte_array, array, (sizeof(array) / sizeof(unsigned int)));
// В прошлой версии этого кода, byte_array объявлялся как byte_array[sizeof(array)], что приводит к тому, что он равен byte_array[2048],
// а должен быть 512. Поэтому размер массива array (ведь unsigned int занимает не 1 байт) нужно поделить на размер unsigned int ( sizeof(unsigned int)).
Данная страница на сайте WikiSort.ru содержит текст со страницы сайта "Википедия".
Если Вы хотите её отредактировать, то можете сделать это на странице редактирования в Википедии.
Если сделанные Вами правки не будут кем-нибудь удалены, то через несколько дней они появятся на сайте WikiSort.ru .