memmove, memmove_s
From cppreference.net
|
定义于头文件
<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
的错误值不会暴露即将发生的缓冲区溢出。
-
与所有边界检查函数相同,仅当实现定义了
__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); // 将[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); // 正确 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); // 计数值大于目标大小 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 函数 (页: TBD)
-
- K.3.7.1.2 memmove_s 函数 (页: 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 函数 (页: 363)
-
- K.3.7.1.2 memmove_s 函数 (页: 615)
- C99标准(ISO/IEC 9899:1999):
-
- 7.21.2.2 memmove函数(页码:326)
- C89/C90 标准 (ISO/IEC 9899:1990):
-
- 4.11.2.2 memmove 函数
参见
|
(C11)
|
复制一个缓冲区到另一个缓冲区
(函数) |
|
(C95)
(C11)
|
在两个可能重叠的数组间复制指定数量的宽字符
(函数) |
|
C++ documentation
for
memmove
|
|