memmove, memmove_s
定义于头文件 <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 数组末尾后的访问则行为未定义。若
dest
或 src
为非法或空指针则行为未定义。2) 同 (1) ,除了错误时清零整个范围 [dest, dest+destsz) (若
dest
和 destsz
均合法)。它在运行时检测下列错误,并调用当前安装的制约处理函数:
-
dest
或src
为空指针 -
destsz
或count
大于 RSIZE_MAX -
count
大于destsz
(会出现溢出)
-
若
dest
所指向的字符数组大小 < count
<= destsz
则行为未定义;换言之, destsz
的错误值不暴露行将发生的缓冲区溢出。
- 同所有边界检查函数,
memmove_s
仅若实现定义 __STDC_LIB_EXT1__ 且用户在包含string.h
前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。
参数
dest | - | 指向复制目的对象的指针 |
destsz | - | 要于目标修改的最大字节数(典型地为目的对象的大小) |
src | - | 指向复制来源对象的指针 |
count | - | 要复制的字节数 |
返回值
1) 返回
dest
的副本,本质为更底层操作的临时内存地址,在实际操作中不建议直接使用此地址,操作完成以后,真正有意义的地址是dest本身。2) 成功时返回零,失败时返回非零值。在失败时,若
dest
不是空指针且 destsz
合法,则亦会写入 destsz
个零字节到目标数组。注解
memmove
可用于设置由分配函数获得的对象的有效类型。
尽管说明了“如同”使用临时缓冲区,此函数的实际实现不会带来二次复制或额外内存的开销。常用方法( glibc 和 bsd libc )是若目标在源之前开始,则从缓冲区开始正向复制,否则从末尾反向复制,完全无重叠时回落到更高效的 memcpy 。
在严格别名时用禁止检验同一内存为二个不同类型的值时,可使用 memmove
转换值。
示例
运行此代码
#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 str[] = "1234567890"; puts(str); memmove(str+4, str+3, 3); // 从 [4,5,6] 复制到 [5,6,7] puts(str); // 设置分配的内存的有效类型为 int int *p = malloc(3*sizeof(int)); // 分配的内存无有效类型 int arr[3] = {1,2,3}; memmove(p,arr,3*sizeof(int)); // 分配的内存现在拥有有效类型 // 转译数据 double d = 0.1; // int64_t n = *(int64_t*)(&d); // 严格别名使用违规 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 大于 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
引用
- C11 standard (ISO/IEC 9899:2011):
- 7.24.2.2 The memmove function (p: 363)
- K.3.7.1.2 The memmove_s function (p: 615)
- C99 standard (ISO/IEC 9899:1999):
- 7.21.2.2 The memmove function (p: 326)
- C89/C90 standard (ISO/IEC 9899:1990):
- 4.11.2.2 The memmove function
参阅
(C11) |
将一个缓冲区复制到另一个 (函数) |
(C95)(C11) |
在两个可能重叠的数组间复制一定数量的宽字符 (函数) |