Namespaces
Variants

memcpy, memcpy_s

From 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