memcpy() 比 memmove() 更快的真正重要情况是什么?

memcpy() 比 memmove() 更快的真正重要情况是什么?

2在大多数情况下,memmove()函数调用的成本与memcpy()在任何定义了它们行为的场景中并没有显著差异。然而,还有两点尚未提及:

1. 在某些实现中,地址重叠的确定可能是昂贵的。在标准C中没有办法确定源对象和目标对象是否指向同一块分配的内存区域,因此不能使用大于号或小于号运算符来比较它们,否则会导致未定义行为。任何实际的实现可能都有一些有效的方法来确定指针是否重叠,但标准并不要求这样的方法存在。完全使用可移植的C编写的memmove()函数在许多平台上执行的时间可能至少是完全使用可移植的C编写的memcpy()函数的两倍。

2. 当不改变语义时,实现允许将函数展开。在80x86编译器上,如果ESI和EDI寄存器没有保持任何重要内容,memcpy(src, dest, 1234)可以生成以下代码:

```

mov esi,[src]

mov edi,[dest]

mov ecx,1234/4 ; 编译器可以注意到它是一个常量

cld

rep movsl

```

这将花费相同数量的内联代码,但比以下代码运行得更快:

```

push [src]

push [dest]

push dword 1234

call _memcpy

...

_memcpy:

push ebp

mov ebp,esp

mov ecx,[ebp+numbytes]

test ecx,3 ; 看看它是否是四的倍数

jz multiple_of_four

multiple_of_four:

push esi ; 不知道调用方是否需要保留此值

push edi ; 不知道调用方是否需要保留此值

mov esi,[ebp+src]

mov edi,[ebp+dest]

rep movsl

pop edi

pop esi

ret

```

相当多的编译器都会对memcpy()进行这样的优化。我不知道有哪些编译器会对memmove()进行这样的优化,尽管在某些情况下,一个优化版本的memcpy()可能提供与memmove相同的语义。例如,如果numbytes为20:

```

; 假设eax、ebx、ecx、edx、esi和edi中的值不需要

mov esi,[src]

mov eax,[esi]

mov ebx,[esi+4]

mov ecx,[esi+8]

mov edx,[esi+12]

mov edi,[esi+16]

mov esi,[dest]

mov [esi],eax

mov [esi+4],ebx

mov [esi+8],ecx

mov [esi+12],edx

mov [esi+16],edi

```

即使地址范围重叠,这也将正常工作,因为它在写入任何部分之前有效地复制(在寄存器中)要移动的整个区域。理论上,编译器可以通过查看是否将memmove()视为memcpy()会产生一个即使地址范围重叠也是安全的实现,并在这些情况下调用_memmove。我不知道有哪些编译器进行了这样的优化。

- supercat

相关文章

FF7竟不是第一!盘点《最终幻想》系列评分最高的游戏

365体育ios 09-02

NVIDIA显卡驱动安装教程(详解NVIDIA显卡驱动的安装步骤和常见问题解决方法)

365体育ios 07-22

博主都在用的拍照修图最全36个app🔥

bet体育365官网正规平台 08-04

镜观中国丨四个关键词回顾中国高铁发展征程

365体育ios 08-21