void memmove ( void * dst, const void * src, size_t count ) {
if ((uintptr_t)src < (uintptr_t)dst) {
// Copy from back to front
} else if ((uintptr_t)dst < (uintptr_t)src) {
// Copy from front to back
}
}
void memcpy ( void * dst, const void * src, size_t count ) {
if ((uintptr_t)src != (uintptr_t)dst) {
// Copy in any way you want
}
}
9条答案
按热度按时间qacovj5a1#
对于
memcpy
,目标根本不能与源重叠。对于memmove
,它可以。这意味着memmove
可能比memcpy
稍微慢一点,因为它不能做出相同的假设。例如,
memcpy
可能总是从低到高复制地址。如果目标地址在源地址之后重叠,这意味着一些地址将在复制之前被覆盖。在这种情况下,memmove
会检测到这一点并在另一个方向复制-从高到低。但是,检查这一点并切换到另一个(可能效率较低)算法需要时间。qybjjes12#
memmove
可以处理重叠内存,memcpy
不能。考虑
显然,源和目标现在重叠了,我们用“bar”覆盖了“-bar”。如果源和目标重叠,那么使用
memcpy
是未定义的行为,因此在本例中我们需要memmove
。kqqjbcuj3#
假设你必须实现这两个,实现可能看起来像这样:
memmove
总是以这样一种方式复制,如果src
和dst
重叠,它仍然是安全的,而memcpy
只是不关心,因为文档说,当使用memcpy
时,两个内存区域不得重叠。例如,如果
memcpy
“从前到后”复制,并且内存块对齐如下将
src
的第一个字节复制到dst
已经破坏了src
的最后一个字节的内容,只有复制“从后到前”才能得到正确的结果。现在交换
src
和dst
:在这种情况下,只有“从前到后”复制才是安全的,因为“从前到后”复制会在复制第一个字节时破坏
src
的前端。你可能已经注意到上面的
memmove
实现甚至没有测试它们是否真的重叠,它只是检查它们的相对位置,但仅凭这一点就可以确保复制安全。由于memcpy
通常使用最快的方式在任何系统上复制内存,因此memmove
通常实现为:有时,如果
memcpy
总是“从前到后”或“从前到后”复制,则memmove
也可能在其中一种重叠情况下使用memcpy
,但memcpy
甚至可能以不同的方式进行复制,具体取决于数据的对齐方式和/或要复制的数据量,因此即使您在系统上测试了memcpy
的复制方式,你不能指望测试结果总是正确的。当你决定打哪一个电话时,这对你意味着什么?
1.除非您确定
src
和dst
不重叠,否则请调用memmove
,因为它将始终导致正确的结果,并且通常与您所需的复印情况一样快。1.如果你确定
src
和dst
不重叠,调用memcpy
,因为你调用哪一个都没有关系,在这种情况下,两者都能正常工作,但是memmove
永远不会比memcpy
快,如果你不走运,它甚至可能更慢,所以你只能调用memcpy
。lpwwtiir4#
来自memcpy手册页。
memcpy()函数将n个字节从内存区域src复制到内存区域dest。内存区域不应该重叠。如果内存区域重叠,请使用memmove(3)。
u0sqgete5#
memmove()
和memcpy()
之间的主要区别是,在memmove()
中使用了一个 buffer -临时内存,因此没有重叠的风险。另一方面,memcpy()
直接将数据从 source 指向的位置复制到 destination 指向的位置。(http://www.cplusplus.com/reference/cstring/memcpy/)考虑以下示例:
1.
如您所料,这将打印出:
1.但在这个例子中,结果将不一样:
输出:
这是因为“memcpy()”执行以下操作:
polhcujo6#
一个(
memmove
)处理重叠的目的地,而另一个(memcpy
)不处理。pbossiut7#
简单地从ISO/IEC:9899标准,它被很好地描述。
7.21.2.1 函数
[...]
2 memcpy函数从s2指向的对象复制n个字符到s1指向的对象。如果复制发生在重叠的对象之间,则行为未定义。
然后呢
7.21.2.2 函数
[...]
2 memmove函数将s2指向的对象中的n个字符复制到s1指向的对象中。复制的发生就好像s2指向的对象中的n个字符首先被复制到一个n个字符的临时数组中,该数组不与s1和s2指向的对象重叠,然后将来自临时数组的N个字符复制到由S1指向的对象中。
我通常根据问题使用哪一个,取决于我需要什么功能。
在纯文本中,
memcpy()
不允许s1
和s2
重叠,而memmove()
允许。66bbxpm58#
实现
mempcpy(void *dest, const void *src, size_t n)
有两种明显的方法(忽略返回值):1.
在第一种实现中,复制从低地址到高地址进行,而在第二种实现中,从高地址到低地址进行。如果要复制的范围重叠(例如,当滚动帧缓冲器时就是这种情况),则只有一个操作方向是正确的,而另一个操作方向将覆盖随后将被读取的位置。
一个
memmove()
的实现,在其最简单的,将测试dest<src
(在一些平台相关的方式),并执行适当的方向的memcpy()
。用户代码当然不能这样做,因为即使将
src
和dst
转换为某种具体的指针类型,它们(通常)也不会指向同一个对象,因此不能进行比较。但是标准库可以有足够的平台知识来执行这样的比较,而不会导致Undefined Behaviour。请注意,在真实的生活中,实现往往要复杂得多,以便从更大的传输(当对齐允许时)和/或良好的数据缓存利用率中获得最大的性能。上面的代码只是为了尽可能简单地说明这一点。
r8uurelv9#
memmove可以处理重叠的源区域和目标区域,而memcpy不能。在两者中,memcpy效率更高。所以,如果可以的话,最好使用memcpy。
参考文献:https://www.youtube.com/watch?v=Yr1YnOVG-4g Jerry Cain博士,(斯坦福大学大学系统介绍讲座-7)时间:三十六点