【问题标题】:Move data in an array will overwrite data?在数组中移动数据会覆盖数据吗?
【发布时间】:2018-01-17 20:05:29
【问题描述】:

我有一个关于 memcpy 的问题。我有一个缓冲区,想将数据从缓冲区的后端移动到前端。像这样的:

int buffer[100];
memcpy(buffer, buffer + 10, 30);

存在重叠数据(元素 11 - 21),是否会丢失数据或将数据复制到前面?这是一个“好习惯”吗?

背景:我在微控制器上有一个大缓冲区,不想重新分配这个缓冲区。它是一个先进先出缓冲区,每次读取某些内容时,后面的数据都会移动到前面。我这样做是为了避免微控制器上的内存碎片。

【问题讨论】:

  • 当缓冲区重叠时使用memmove
  • 顺便说一句,通过查看man memcpy,这样的问题通常更快得到解决。
  • manual pagememcpy 的表述非常清楚:memcpy() 函数将n 字节从内存区域src 复制到内存区域dest内存区域不能重叠。如果内存区域重叠,请使用memmove(3)这实际上是对函数的完整描述。
  • 在速度方面,“每次读到东西,后面的数据都会移到前面”。听起来那是真正的性能问题。这听起来肯定是错误的设计选择。我建议重新检查设计,而不是担心memcpy()memmove() 与精心设计的代码的微优化。
  • 在我的情况下,速度并不重要

标签: c memcpy


【解决方案1】:

memcpy 的手册明确指出,当缓冲区重叠时不要使用它,在这种情况下您应该使用 memmove

memcpy() 函数将 n 个字节从内存区域 src 复制到内存区域 dest。内存区域不得重叠。如果内存区域确实重叠,请使用 memmove(3)。

为了完整起见,这里是memmove的描述:

memmove() 函数将 n 个字节从内存区域 src 复制到内存区域 dest。内存区域可能会重叠:复制就像首先将 src 中的字节复制到不与 src 重叠的临时数组中一样 或 dest,然后将字节从临时数组复制到 dest。

【讨论】:

  • 不会造成内存碎片吗?
  • 不,只有一个临时缓冲区用于防止覆盖尚未复制的数据。内存最终还是被复制到同一个地方。
  • 是的,但我在一个 2k 内存的控制器上工作。会发生什么,例如如果我的缓冲区是 128 字节并且没有 128 字节的临时数组可以分配为临时数组?在这种情况下,编写一个将在重叠区域中按字节复制的函数不是更好吗?
  • 嗯,这可能归结为实施。我认为最好假设memmove 是要走的路,直到证明并非如此。也许在您的平台上查看memmove 的实现以获得更好的想法。
  • 根据 arduino 论坛中的帖子,最好手动复制字节,因为 memmove 开销相当昂贵......这就是为什么我希望 memcpy 能够工作......
【解决方案2】:

memcpy 是这个任务的错误函数:

man memcpy, man memmove

#include <string.h>

void *memcpy(void *dest, const void *src, size_t n);
void *memmove(void *dest, const void *src, size_t n);

memcpy() 函数将n 字节从内存区域src 复制到内存区域dest内存区域不能重叠。如果内存区域重叠,请使用memmove(3)

memmove() 函数将n 字节从内存区域src 复制到内存区域dest内存区域可能重叠:复制就像src 中的字节是 首先复制到不重叠srcdest 的临时数组中,然后将字节 然后从临时数组复制到dest

【讨论】:

    【解决方案3】:

    这是一个“好习惯”吗?

    这是未定义的行为,所以不要这样做。

    使用专门为此设计的memmove()

    描述

    memmove()函数将n个字节从内存区src复制到内存中 区域目的地内存区域可能重叠:复制发生在 虽然 src 中的字节首先被复制到一个临时数组中 不重叠 src 或 dest,然后从 到 dest 的临时数组。

    以下段落摘自 memcpy() 的手册页,明确指出 POSIX 和 C 标准都是明确的,因为在重叠区域使用 memcpy() 是未定义的行为。 p>

    注意事项

    未遵守内存区域不存在的要求 重叠一直是重大错误的根源。 (POSIX 和 C 标准明确规定使用具有重叠区域的 memcpy() 产生未定义的行为。)最值得注意的是,在 glibc 2.13 a memcpy() 在某些平台上的性能优化(包括 x86-64) 包括更改从中复制字节的顺序 src 到 dest。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-06-25
      • 1970-01-01
      • 2019-04-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-07
      相关资源
      最近更新 更多