7

有人可以帮助我理解 memmove 是如何在 C 中实现的。我只有一个特殊条件吗?

if((src<dst)&&((src+sz) > dst))

copy from the back

它还取决于堆栈的增长方式吗?

4

3 回答 3

32

从数学上讲,您根本不必担心它们是否重叠。如果src小于dst,则从末尾复制。如果src大于dst,则从头开始复制。

如果srcdst相等,则直接退出。

那是因为您的案例是以下情况之一:

1) <-----s----->                start at end of s
                 <-----d----->

2) <-----s----->                start at end of s
            <-----d----->

3) <-----s----->                no action
   <-----d----->

4)          <-----s----->       start at beginning of s
   <-----d----->

5)               <-----s----->  start at beginning of s
   <-----d----->

即使没有重叠,它仍然可以正常工作,并简化您的条件。

If you have a more efficient way to copy forwards than backwards then, yes, you should check for overlap to ensure you're using the more efficient method if possible. In other words, change option 1 above to copy from the beginning.

于 2010-08-26T06:25:10.827 回答
6

如果两个内存区域不重叠,则memmove可以变成一个 memcpy。显然,memcpy 在大多数系统上都经过了极大的优化(我使用的其中一个几乎利用了书中的所有技巧,从展开循环到支持最大吞吐量的 SSE 操作)。

如果两个内存区域确实重叠,则出于所有意图和目的,将要复制的区域移动到临时缓冲区中,并将临时缓冲区(最有可能全部使用 memcpy)复制回原始缓冲区的顶部。您不能从头开始工作,也不能在重叠区域的后面工作,因为在此过程中您总是会至少有一些数据被损坏。

话虽这么说,我已经很久没有看 libc 代码了,所以可能有一个我还没有想到的 memmove 和重叠区域的优化。

memmove 根本不依赖于堆栈的增长方式——它只是将一个内存区域复制到另一个位置——就像 memcpy 一样,除了它处理重叠区域而 memcpy 不处理。

编辑:实际上,再想一想......如果你从正确的“来源”(可以这么说)开始,从后面工作可以工作,这取决于移动本身(例如,来源 < dest 与否?)。你可以在这里阅读 newlib 的实现,而且 tt 的评论也相当不错。

于 2010-08-26T05:53:57.367 回答
2

取决于编译器。好的编译器会根据目标处理器指令集和总线宽度使用好的优化。

于 2010-08-26T05:52:15.537 回答