【问题标题】:Which one to use - memmove() or memcpy() - when buffers don't overlap?使用哪一个 - memmove() 或 memcpy() - 当缓冲区不重叠时?
【发布时间】:2010-12-29 23:31:02
【问题描述】:

当源和目标重叠时使用 memcpy() 会导致未定义的行为 - 在这些情况下,只能使用 memmove()

但是如果我确定缓冲区不重叠怎么办 - 是否有理由专门使用 memcpy() 或专门使用 memmove()?我应该使用哪个?为什么?

【问题讨论】:

  • 如果我的生活依赖它,我不会使用std::copy
  • @Matt Joiner:你能解释一下你为什么这么不喜欢std::copy()吗?
  • 这是糖衣,并没有带来特别的性能提升。此外,它更难用肉眼解析,并且占用更多空间(std::copy 可以占用 160 个字符)。唯一的好处是它为你包装了一个循环,这很容易出错。但有可能知道 std::copy 的人能够正确地循环。
  • 小心关于性能的断言,@MattJoiner。 stackoverflow.com/questions/4707012/c-memcpy-vs-stdcopy/…
  • @MattJoiner:虽然这是一个老问题,但我想提一下,STL 中最接近std::memmove/std::memcpy 的不是std::copy,而是std::copy_n,它可以接受相同的输入参数,甚至可能输入更少,因为您不需要 sizeof 并且 - 此外 - 适用于任何类型。顺便说一句:我真的不明白,你是如何得到 160 个字符的。

标签: c++ c memory


【解决方案1】:

memcpy() 对重叠缓冲区没有任何特殊处理,因此它缺少一些检查,因此它比memmove() 更快。

此外,在某些架构上,memcpy() 可以从使用 CPU 指令移动内存块中受益——这是memmove() 无法使用的。

【讨论】:

  • 即使在 RISC 架构上,通常也有 memcpy() 可以从中受益的块移动操作。例如,PowerPC 有 VMX。
  • 不,体面的代码生成器会在检查无重叠后生成 rep mov。 MSVC 可以。
  • @nobugz 并非总是在编译时可以确定缓冲区是否重叠。还是您的意思是在运行时检查?
  • @Crashworks 有趣,不知道。似乎我有更多 RISCy RISC 的经验,它们只有加载/存储指令来访问内存。
  • @qrdl:RISC 没有 rep mov,但许多 RISC 架构的向量寄存器比标量核心寄存器更宽,并且具有相应更宽的进出内存的路径。
【解决方案2】:

如果您对哪个性能更好感兴趣,您需要在目标平台上对其进行测试。标准中没有规定如何实现这些功能,虽然不检查 ​​memcpy 会更快似乎是合乎逻辑的,但这绝不是肯定的。

很有可能,尽管不太可能,为您的特定编译器编写 memmove 的人是经过认证的天才,而获得编写 memcpy 工作的可怜人是村里的白痴:-)

尽管在现实中,我很难想象memmove 会比memcpy 更快,但我不排除这种可能性。 衡量,不要猜测。

【讨论】:

  • memcpy 的参数有限制限定符,而不是 memmove。 (它准确地说明了缓冲区不重叠的事实)。
  • 哦!你是对的,当然,@StephenC,我把它们弄错了。从我的答案中删除了那个废话:-)
【解决方案3】:

假设一个理智的库实现者,memcpy 将始终至少与memmove 一样快。但是,在大多数平台上差异很小,并且在许多平台上memcpy 只是memmove 的别名,以支持在重叠缓冲区上(错误地)调用memcpy 的遗留代码。

memcpymemmove 都应该编写为利用平台上最快的加载和存储。

回答您的问题:您应该使用语义正确的那个。如果可以保证缓冲区不重叠,则应使用memcpy。如果你不能保证缓冲区不重叠,你应该使用memmove

【讨论】:

  • +1。我特别喜欢“假设理智”与我自己的回答相对应:-)
  • Nitpick: memcpymemmove 应该被编写以利用平台上最快的 unaligned 加载和存储。如果您知道缓冲区已正确对齐,则通常可以使用 MMX 之类的东西获得更好的性能,它一次复制更大的数据单元。
  • @Adam:一般来说,通过首先复制一些较小的单元来实现适当的对齐,可以安排在 memcopy 中使用对齐的加载和存储。如果缓冲区没有类似的对齐方式,则需要在存储之前应用一些移位或置换,但这比在许多架构上使用未对齐的内存访问要快。
  • @StephenCanon:我想知道未来的 C 标准是否会有任何问题,选择一些以前从未使用过的标识符并说任何定义名称为 __uint32_copy_xy193qrq91 [或其他其他类型的类似名称] 必须实现它以具有某些特定的语义,然后将其定义为复制对齐的int32 数据的新标准方法的名称。这样做可以编写在旧编译器上正常工作的代码,但在较新的编译器上可以实现比 memcpy 更快的性能 [memcpy() 通常...
  • ...当程序员(而不是编译器)知道这样的循环可以工作时,只复制几个字的数据时,效率比简单的 uint32 复制循环低。 memcpy() 的实现通常针对对齐到对齐的场景进行优化,但测试对齐所需的时间可能会超过实际复制几个字数据所需的时间。
【解决方案4】:

在我正在开发的某些 ARM 平台上,对于短时间未对齐的负载,memmove 比 memcpy 快 3 倍。由于 memcpy 和 memmove 是唯一真正可移植的类型双关语机制,您可能会认为编译器会在尝试使用 NEON 之前进行一些检查。

【讨论】:

    猜你喜欢
    • 2014-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-29
    • 2021-12-14
    • 2010-11-08
    • 2014-04-03
    相关资源
    最近更新 更多