如果目的地和来源相同,memmove
是否仍然“移动”数据(或直接返回)?怎么样realloc
;如果新尺寸与旧尺寸相同怎么办?
答案 0 :(得分:2)
这真的是特定于实现的。当然,这样做是好的做法,但这实际上取决于你的意思实现。
它可以以任何一种方式工作,但可能是一个适当聪明的实现会检查重叠的段(特别是source == dest
的情况)并适当地处理它。
答案 1 :(得分:1)
据我所知,在这种情况下,没有标准给出任何关于立即返回的承诺,所以你不应该期待这种行为。
最好不要传递无效指针,希望它不会访问数据; - )
答案 2 :(得分:0)
至少对于realloc
,隐含地假设存在“无需移动”条件且有效,因为移动被视为特殊情况:
realloc()函数应将ptr指向的内存对象的大小更改为size指定的大小。对象的内容应保持不变,直至新旧尺寸中的较小者。 如果内存对象的新大小需要移动对象,则释放该对象的先前实例化的空间。
措辞“if ...... would”表示这并不总是如此。当然,对于省略不必要的副本的实现,根本没有没有要求。
memmove
的唯一要求是最终效果与首先将数据复制到临时缓冲区然后复制到最终目标的效果相同。这种“仿佛”约束允许在不破坏数据的情况下复制重叠区域(我知道实际首先没有实现复制到临时缓冲区)。
所以,用一个词来说:未指明。
答案 3 :(得分:0)
正如其他人所说,该规范不需要快捷方式,也不清楚何时添加额外的分支实际上可以提高性能。
但是,这并不能回答调用memmove
时实际发生的问题。我仔细研究了glibc源代码,发现了许多用于各种体系结构的汇编实现以及可移植的C实现。
TL; DR的意思是纯C版本没有捷径,但x86_64汇编版本却有捷径。
纯C版本是一个相当标准的记忆循环。一种技巧是,如果您要移动16 KiB或更多,它将操纵虚拟内存而不是复制字节。该函数在string/memmove.c中定义,实现的内容是sysdeps/generic/memcopy.h中的BYTE_COPY_FWD
宏。
对于x86_64汇编,根据可用说明(例如AVX,SSE等)有多个版本。这些在sysdeps/x86_64/multiarch中。
这是memmove-vec-unaligned-erms.S中的一种使用增强型REP MOVSB(ERMS)的实现:
ENTRY (__memmove_erms)
movq %rdi, %rax
/* Skip zero length. */
test %RDX_LP, %RDX_LP
jz 2f
L(start_movsb):
mov %RDX_LP, %RCX_LP
cmp %RSI_LP, %RDI_LP
jb 1f
/* Source == destination is less common. */
je 2f
lea (%rsi,%rcx), %RDX_LP
cmp %RDX_LP, %RDI_LP
jb L(movsb_backward)
1:
rep movsb
2:
ret
L(movsb_backward):
leaq -1(%rdi,%rcx), %rdi
leaq -1(%rsi,%rcx), %rsi
std
rep movsb
cld
ret
END (__memmove_erms)
我的读取程序集的能力并不强,但是据我所知,此实现确实简化了源和目标相同的情况。
如果我正确地阅读了此内容,则首先比较指针。如果目的地在源之前,它将跳转到标签1(jb 1f
),该标签将调用rep movsb
。据我了解,这基本上是memcpy
的说明。如果指针相等,则跳转到标签2(je 2f
),该标签立即返回。否则,它将安排rep movsb
向后运行数据。
我还查看了sysdeps/x86_64/multiarch/memcpy-ssse3.S中的SSSE3实现。该版本似乎也实现了快捷方式。
很显然,所有这些仅适用于glibc。我还没有检查llvm-libc。