Namespaces
Variants

memcpy, memcpy_s

From zh.cppreference.net
< c ‎ | string ‎ | byte
定义于头文件 <string.h>
(1)
void * memcpy ( void * dest, const void * src, size_t count ) ;
(C99前)
void * memcpy ( void * restrict dest, const void * restrict src, size_t count ) ;
(C99起)
errno_t memcpy_s ( void * restrict dest, rsize_t destsz,
const void * restrict src, rsize_t count ) ;
(2) (C11起)
1) 从 src 指向的对象复制 count 个字符到 dest 指向的对象。两个对象均被解释为 unsigned char 类型的数组。
若访问发生在 dest 数组末尾之后,则行为未定义。若对象重叠 (这违反了 restrict 约定) (C99 起) ,则行为未定义。若 dest 或 src 为无效指针或空指针,则行为未定义。
2) 与 (1) 相同,但在运行时检测到以下错误时,会使整个目标范围 [ dest, dest + destsz ) 被清零(若 dest 和 destsz 均有效),并调用当前安装的 约束处理函数 :
  • dest 或 src 是空指针
  • destsz 或 count 大于 RSIZE_MAX
  • count 大于 destsz (将发生缓冲区溢出)
  • 源对象与目标对象存在重叠
若 dest 所指向的字符数组大小满足 < count <= destsz ,则行为未定义;换言之, destsz 的错误值不会暴露即将发生的缓冲区溢出。
与所有边界检查函数一样,仅当实现定义了 __STDC_LIB_EXT1__ 且用户在包含 <string.h> 前将 __STDC_WANT_LIB_EXT1__ 定义为整型常量 1 时,才保证 memcpy_s 可用。

目录

参数

dest - 指向目标对象的指针
destsz - 目标对象中允许修改的最大字节数(通常为目标对象的尺寸)
src - 指向源对象的指针
count - 需要复制的字节数

返回值

1) 返回 dest 的副本
2) 成功时返回零,错误时返回非零值。在发生错误时,如果 dest 不是空指针且 destsz 有效,则向目标数组写入 destsz 个零字节。

注释

memcpy 可用于设置通过分配函数获取的对象的 有效类型 。

memcpy 是内存到内存复制的最快库例程。它通常比必须扫描所复制数据的 strcpy 或必须处理重叠输入情况的 memmove 更高效。

多个C编译器会将合适的内存复制循环转换为 memcpy 调用。

当 严格别名规则 禁止以两种不同类型的形式检查同一块内存时,可使用 memcpy 进行值转换。

示例

#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 source[] = "once upon a midnight dreary...", dest[4];
    memcpy(dest, source, sizeof dest);
    for(size_t n = 0; n < sizeof dest; ++n)
        putchar(dest[n]);
    // 将分配内存的有效类型设置为 int
    int *p = malloc(3*sizeof(int));   // 分配的内存尚无有效类型
    int arr[3] = {1,2,3};
    memcpy(p,arr,3*sizeof(int));      // 分配的内存现在具有有效类型
    // 重新解释数据
    double d = 0.1;
//    int64_t n = *(int64_t*)(&d); // 严格别名违规
    int64_t n;
    memcpy(&n, &d, sizeof d); // 正确
    printf("\n%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 = memcpy_s(dst,sizeof dst,src,5);
    printf("dst = \"%s\", r = %d\n", dst,r);
    r = memcpy_s(dst,5,src,10);            //  count 大于 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
}

可能的输出:

once
0x1.999999999999ap-4 is 3fb999999999999a as an int64_t
dst = "aaaaayxyxy", r = 0
dst = "\0\0\0\0\0yxyxy", r = 22

参考文献

  • C11 标准 (ISO/IEC 9899:2011):
  • 7.24.2.1 memcpy 函数 (第 362 页)
  • K.3.7.1.1 memcpy_s 函数 (第 614 页)
  • C99 标准 (ISO/IEC 9899:1999):
  • 7.21.2.1 memcpy 函数 (第 325 页)
  • C89/C90 标准 (ISO/IEC 9899:1990):
  • 4.11.2.1 memcpy 函数

另请参阅

(C23)
复制一个缓冲区到另一个缓冲区,遇到指定分隔符后停止
(函数)
移动一个缓冲区到另一个缓冲区
(函数)
在两个非重叠数组间复制指定数量的宽字符
(函数)
C++ 文档 for memcpy