C memmove_s 函数
最后修改:2025 年 4 月 8 日
内存操作在 C 编程中至关重要,而 memmove_s 是一个用于在内存位置之间移动数据的安全函数。本教程将深入介绍 memmove_s,包括其语法、用法和优点。我们将探讨实际示例,并将其与不安全的替代方案进行比较。理解 memmove_s 有助于在现代 C 程序中编写安全可靠的内存操作。
什么是 memmove_s?
memmove_s 函数可以将内存块安全地从一个位置移动到另一个位置。它在 string.h 中声明,并接受五个参数:目标指针、目标大小、源指针、要移动的字节数以及可选的错误处理程序。与 memmove 不同,它执行边界检查以防止缓冲区溢出。它是 C11 的 Annex K 边界检查接口的一部分。在安全性很重要的情况下,请始终优先使用 memmove_s 而不是 memmove。
memmove_s 基本用法
此示例演示了使用 memmove_s 在两个数组之间安全移动数据。
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <string.h>
int main() {
char src[] = "Hello, World!";
char dest[20];
// Safely move 14 bytes (including null terminator)
errno_t result = memmove_s(dest, sizeof(dest), src, 14);
if (result != 0) {
printf("Error moving memory: %d\n", result);
return 1;
}
printf("Source: %s\n", src);
printf("Destination: %s\n", dest);
return 0;
}
在此,memmove_s 将 14 个字节从 src 移动到 dest,包括空终止符。该函数会检查目标缓冲区是否足够大。如果成功,则返回零;否则,返回错误代码。当您知道确切所需大小时,这是移动数据的安全方法。
处理重叠内存区域
此示例演示了 memmove_s 如何安全地处理重叠区域。
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <string.h>
int main() {
char data[20] = "ABCDEFGHIJ";
// Safely move with overlapping regions
errno_t result = memmove_s(data + 2, sizeof(data) - 2, data, 5);
if (result != 0) {
printf("Error moving memory: %d\n", result);
return 1;
}
printf("Result: %s\n", data);
return 0;
}
此代码安全地在重叠区域内移动数据。memmove_s 在确保不发生缓冲区溢出的同时正确处理重叠。目标大小参数可防止写入超出缓冲区边界。此行为使 memmove_s 在安全性方面优于 memcpy 和 memmove。
使用 memmove_s 移动结构
memmove_s 可以安全地移动整个结构,如下面的示例所示。
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <string.h>
typedef struct {
int id;
char name[20];
float score;
} Student;
int main() {
Student s1 = {101, "Alice", 95.5};
Student s2;
// Safely move the entire structure
errno_t result = memmove_s(&s2, sizeof(Student), &s1, sizeof(Student));
if (result != 0) {
printf("Error moving structure: %d\n", result);
return 1;
}
printf("Moved Student:\n");
printf("ID: %d\n", s2.id);
printf("Name: %s\n", s2.name);
printf("Score: %.1f\n", s2.score);
return 0;
}
此示例使用 memmove_s 移动一个 Student 结构。sizeof 运算符确保我们移动了所需的精确字节数。该函数会验证目标是否有足够的空间。此方法对于移动结构来说是安全有效的。请注意,它最适用于没有内部指针的简单结构。
部分数组移动
此示例演示了如何使用 memmove_s 安全地移动数组的一部分。
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <string.h>
int main() {
int src[] = {1, 2, 3, 4, 5, 6, 7, 8};
int dest[4];
// Safely move middle 4 elements (3,4,5,6)
errno_t result = memmove_s(dest, sizeof(dest), src + 2, 4 * sizeof(int));
if (result != 0) {
printf("Error moving array portion: %d\n", result);
return 1;
}
printf("Moved elements: ");
for (int i = 0; i < 4; i++) {
printf("%d ", dest[i]);
}
printf("\n");
return 0;
}
在这里,memmove_s 将从源数组的第三个元素开始的四个整数移动。大小计算为 4 * sizeof(int) 以获得正确的字节数。该函数会验证目标数组是否有足够的空间。此技术对于安全地提取数组或缓冲区的一部分非常有用。
memmove_s 的错误处理
此示例演示了 memmove_s 的全面错误处理。
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <string.h>
#include <errno.h>
void handle_memmove_error(errno_t err) {
switch (err) {
case EINVAL:
printf("Invalid parameters\n");
break;
case ERANGE:
printf("Destination buffer too small\n");
break;
default:
printf("Unknown error: %d\n", err);
}
}
int main() {
char big[20] = "Large buffer";
char small[5];
// Attempt to move too much data
errno_t result = memmove_s(small, sizeof(small), big, sizeof(big));
if (result != 0) {
handle_memmove_error(result);
return 1;
}
printf("Move successful\n");
return 0;
}
此代码显示了 memmove_s 的正确错误处理。该函数返回特定的错误代码,可以对其进行检查和适当处理。EINVAL 表示参数无效,而 ERANGE 表示目标太小。健壮的错误处理使程序更可靠、更安全。始终检查 memmove_s 的返回值。
使用 memmove_s 的最佳实践
- 始终检查返回值:在使用移动的数据之前,请验证操作是否成功。
- 使用正确的缓冲区大小:确保目标大小参数与实际缓冲区大小匹配。
- 优先于 memmove:在安全性很重要的情况下,请使用
memmove_s。 - 初始化缓冲区:如果可能,请初始化目标缓冲区以获得更好的调试。
- 考虑平台支持:验证
memmove_s在您的目标平台上是否可用。
来源
本教程从基本用法到高级错误处理,对 memmove_s 函数进行了探讨。作为 memmove 的安全替代方案,它为内存操作提供了重要的安全检查。在安全性至关重要的代码中,请始终优先使用边界检查的函数,以防止漏洞。
作者
列表 C 标准库。