ZetCode

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 在两个数组之间安全移动数据。

basic_move.c
#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 如何安全地处理重叠区域。

overlap_move.c
#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 在安全性方面优于 memcpymemmove

使用 memmove_s 移动结构

memmove_s 可以安全地移动整个结构,如下面的示例所示。

struct_move.c
#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 安全地移动数组的一部分。

partial_move.c
#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 的全面错误处理。

error_handling.c
#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 的最佳实践

来源

C memmove_s 文档

本教程从基本用法到高级错误处理,对 memmove_s 函数进行了探讨。作为 memmove 的安全替代方案,它为内存操作提供了重要的安全检查。在安全性至关重要的代码中,请始终优先使用边界检查的函数,以防止漏洞。

作者

我叫 Jan Bodnar,是一名敬业的程序员,对编码充满热情。自 2007 年以来,我通过 1,400 多篇文章和 8 本电子书分享了我的专业知识。凭借十多年的教学经验,我致力于使编程易于理解且引人入胜。

列表 C 标准库