命名空间
变体
操作

memmove, memmove_s

来自 cppreference.cn
< c‎ | string‎ | byte
定义于头文件 <string.h>
void* memmove( void* dest, const void* src, size_t count );
(1)
errno_t memmove_s(void* dest, rsize_t destsz, const void* src, rsize_t count);
(2) (自 C11 起)
1)src 指向的对象复制 count 个字符到 dest 指向的对象。两个对象都被解释为 unsigned char 的数组。对象可能重叠:复制的发生方式如同字符被复制到一个临时的字符数组,然后字符从该数组复制到 dest
如果访问发生在 dest 数组末尾之外,则行为未定义。如果 destsrc 是无效或空指针,则行为未定义。
2)(1) 相同,除了在运行时检测到以下错误时,它会将整个目标范围 [dest, dest + destsz) (如果 destdestsz 都是有效的)清零,并调用当前安装的 约束处理函数
  • destsrc 是空指针
  • destszcount 大于 RSIZE_MAX
  • count 大于 destsz (会发生缓冲区溢出)
如果 dest 指向的字符数组的大小 < count <= destsz,则行为未定义;换句话说,destsz 的错误值不会暴露即将发生的缓冲区溢出。
与所有边界检查函数一样,只有当实现定义了 __STDC_LIB_EXT1__ 并且用户在包含 <string.h> 之前将 __STDC_WANT_LIB_EXT1__ 定义为整数常量 1 时,才能保证 memmove_s 可用。

目录

[编辑] 参数

dest - 指向要复制到的对象的指针
destsz - 目标中要修改的最大字节数(通常是目标对象的大小)
src - 指向要复制的对象的指针
count - 要复制的字节数

[编辑] 返回值

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

[编辑] 注解

memmove 可用于设置通过分配函数获得对象的有效类型

尽管被指定为“如同”使用临时缓冲区,但此函数的实际实现不会产生开销或双重复制或额外的内存。一种常见的方法(glibc 和 bsd libc)是如果目标在源之前开始,则从缓冲区的开头向前复制字节,否则从末尾向后复制,并在根本没有重叠时回退到更高效的 memcpy

严格别名 禁止将同一内存作为两种不同类型的值进行检查的情况下,memmove 可用于转换值。

[编辑] 示例

#define __STDC_WANT_LIB_EXT1__ 1
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
int main(void)
{
    char str[] = "1234567890";
    puts(str);
    memmove(str + 4, str + 3, 3); // copy from [4,5,6] to [5,6,7]
    puts(str);
 
    // setting effective type of allocated memory to be int
    int* p = malloc(3 * sizeof(int)); // allocated memory has no effective type
    int arr[3] = {1, 2, 3};
    memmove(p, arr, 3 * sizeof(int)); // allocated memory now has an effective type
 
    // reinterpreting data
    double d = 0.1;
    // int64_t n = *(int64_t*)(&d); // strict aliasing violation
    int64_t n;
    memmove(&n, &d, sizeof d); // OK
    printf("%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 = memmove_s(dst, sizeof dst, src, 5);
    printf("dst = \"%s\", r = %d\n", dst, r);
    r = memmove_s(dst, 5, src, 10); // count is greater than 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
}

可能的输出

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

[编辑] 参考文献

  • C23 标准 (ISO/IEC 9899:2024)
  • 7.24.2.2 memmove 函数 (p: TBD)
  • K.3.7.1.2 memmove_s 函数 (p: TBD)
  • C17 标准 (ISO/IEC 9899:2018)
  • 7.24.2.2 memmove 函数 (p: 264)
  • K.3.7.1.2 memmove_s 函数 (p: 446)
  • C11 标准 (ISO/IEC 9899:2011)
  • 7.24.2.2 memmove 函数 (p: 363)
  • K.3.7.1.2 memmove_s 函数 (p: 615)
  • C99 标准 (ISO/IEC 9899:1999)
  • 7.21.2.2 memmove 函数 (p: 326)
  • C89/C90 标准 (ISO/IEC 9899:1990)
  • 4.11.2.2 memmove 函数

[编辑] 参见

将一个缓冲区复制到另一个缓冲区
(函数) [编辑]
在两个可能重叠的数组之间复制一定数量的宽字符
(函数) [编辑]
C++ 文档 关于 memmove