有人可以帮助我理解 memmove 是如何在 C 中实现的。我只有一个特殊条件吗?
if((src<dst)&&((src+sz) > dst))
copy from the back
它还取决于堆栈的增长方式吗?
从数学上讲,您根本不必担心它们是否重叠。如果src
小于dst
,则从末尾复制。如果src
大于dst
,则从头开始复制。
如果src
和dst
相等,则直接退出。
那是因为您的案例是以下情况之一:
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.
如果两个内存区域不重叠,则memmove可以变成一个 memcpy。显然,memcpy 在大多数系统上都经过了极大的优化(我使用的其中一个几乎利用了书中的所有技巧,从展开循环到支持最大吞吐量的 SSE 操作)。
如果两个内存区域确实重叠,则出于所有意图和目的,将要复制的区域移动到临时缓冲区中,并将临时缓冲区(最有可能全部使用 memcpy)复制回原始缓冲区的顶部。您不能从头开始工作,也不能在重叠区域的后面工作,因为在此过程中您总是会至少有一些数据被损坏。
话虽这么说,我已经很久没有看 libc 代码了,所以可能有一个我还没有想到的 memmove 和重叠区域的优化。
memmove 根本不依赖于堆栈的增长方式——它只是将一个内存区域复制到另一个位置——就像 memcpy 一样,除了它处理重叠区域而 memcpy 不处理。
编辑:实际上,再想一想......如果你从正确的“来源”(可以这么说)开始,从后面工作可以工作,这取决于移动本身(例如,来源 < dest 与否?)。你可以在这里阅读 newlib 的实现,而且 tt 的评论也相当不错。
取决于编译器。好的编译器会根据目标处理器指令集和总线宽度使用好的优化。