0%

memcpy()地址重叠

memcpy(), 如果源区间和目的区间有重叠时, 它的行为会怎么样?

首先 man memcpy,看一下相关描述:

description

note

从网上又找到memcpy的定义:

1
2
void *memcpy(void *dst, const void *src, size_t n);
//If copying takes place between objects that overlap, the behavior is undefined.

对于地址重叠的情况,该函数的行为是未定义的。

代码测试

test

尴尬了……理论上不该是这样的正确结果啊……

知乎上说结果会是“hhhhhhhhhhhhhh”,还分析了一大波。

fugai

其实关键就在于,对于上面两种情况,从高地址还是低地址开始拷贝。

如果要自己实现这个函数的话,判断源地址和目的地址的大小,才决定到底是从高地址开始拷贝还是低地址开始拷贝。

看看memcpy()的源码,其实就是这样实现滴。(Linux v5.5.9 https://elixir.bootlin.com/linux/latest/source/arch/alpha/lib/memcpy.c

1
2
3
4
5
6
7
8
9
10
11
void *memcpy(void *dst, const void *src, size_t len)
void * memcpy(void * dest, const void *src, size_t n)
{
if (!(((unsigned long) dest ^ (unsigned long) src) & 7)) {
__memcpy_aligned_up ((unsigned long) dest, (unsigned long) src,
n);
return dest;
}
__memcpy_unaligned_up ((unsigned long) dest, (unsigned long) src, n);
return dest;
}

光是下面这样的话,会有问题啊。(git://gcc.gnu.org/git/gcc.git)

1
2
3
4
5
6
7
8
9
10
11
12

/* Public domain. */
#include <stddef.h>
void *
memcpy (void *dest, const void *src, size_t len)
{
char *d = dest;
const char *s = src;
while (len--)
*d++ = *s++;
return dest;
}

android / kernel / lk / master / . / lib / libc / string / memcpy.c这里面倒没看见有判断。