【问题标题】:Performance of memmove compared to memcpy twice?memmove 的性能是 memcpy 的两倍?
【发布时间】:2017-12-11 11:41:17
【问题描述】:

我已经看到What is the difference between memmove and memcpy? 中接受的答案指出的差异,它说memmove might be very slightly slower than memcpy

我们可以通过以下方式实现memmove 的替代方案:分配一个临时缓冲区,然后memcpy 两次(src -> tmp, tmp -> dest)。我的问题是:哪种方式更快,memmove 还是其他方式?

【问题讨论】:

  • 这取决于目标机器和实现。
  • 复制数据很慢。复制数据 两次 会比较慢。 memmove 可能memcpy慢是因为它能够处理重叠内存,但memmove仍然只复制数据一次
  • 在您对时间感兴趣的平台上对其进行分析。然而,你写出比 memmove 更好的 memmove 的可能性似乎不大。
  • 您平台的标准memmove 很可能已经高度优化,所以如果源和目标可能重叠,请使用memmove,不要打扰。如果您确定源和目标永远不会重叠,那么只需使用memcpy

标签: c++ c memcpy memmove


【解决方案1】:

来自http://en.cppreference.com/w/cpp/string/byte/memmove

尽管指定“好像”使用临时缓冲区,但此函数的实际实现不会产生双重复制或额外内存的开销。对于小计数,它可能会加载和写出寄存器;对于较大的块,一种常见的方法(glibc 和 bsd libc)是如果目标在源之前开始,则从缓冲区的开头向前复制字节,否则从结尾向后复制,当有时回退到 std::memcpy完全没有重叠。

因此,开销很可能是几个条件分支。对于大块来说几乎不值得担心。

但是,值得记住的是,std::memcpy 是一个“魔法”函数,是在两种不同类型之间进行转换的唯一合法方式。

在 c++ 中,这是非法的(未定义的行为):

union {
  float a;
  int b;
} u;

u.a = 10.0;
int x = u.b;

这是合法的:

float a = 10.0;
int b;
std::memcpy(std::addressof(b), std::addressof(a), size(b));

如果你是一名 C 程序员,你会做你期望工会做的事情。

【讨论】:

    【解决方案2】:

    std::memmove "可能比std::memcpy非常轻微"(强调),因为它必须首先检查源和目标范围是否重叠。在内部,这只是几个指针比较;完成后,如果没有重叠或目标从源下方开始,它会调用std::memcpy;否则,它会调用 std::memcpy 的变体,从结尾向开头复制。

    简而言之,这里唯一的区别在于初始比较;一旦完成,就像std::memcpy。不需要额外的缓冲区并将所有内容复制两次。

    【讨论】:

      【解决方案3】:

      Memcpy 通常更快,因为它不假设目标和源可能重叠。

      因此,如果您尝试使用 memcpy 将字符串 abcd 从位置 X 复制到 X+2,则可能会得到这样的结果

      X: A B C D
      

      memcpy 之后

      X+2 A B A A
      

      虽然 memmove 会保证不会丢失任何内容,因为它使用中间缓冲区来存储原始字符串。

      另一方面,您可以将限定符 restrict 用于源和目标,这样您可以告诉 memmove 源和目标没有重叠,这样 memmove 可以选择其他更快的算法以防万一使用这个限定词。

      详情见here

      【讨论】:

        猜你喜欢
        • 2013-08-13
        • 2011-05-23
        • 1970-01-01
        • 2016-06-09
        • 2011-04-17
        • 2021-04-03
        • 1970-01-01
        • 1970-01-01
        • 2011-07-21
        相关资源
        最近更新 更多