这是一个出于好奇而不是重要的问题,但我只想知道memmove
文档中的以下代码段:
复制发生,好像使用了中间缓冲区
(强调我的)。该公式告诉我,是否使用了中间缓冲区,特定于编译器实现。
如果您要我写memmove
,我可能会自动执行以下操作:
n
个字节memcpy
临时来源memcpy
到达目的地的临时工具我希望有人能......
gcc
或Visual C ++)中的实际实现有所了解 - 例如, 它使用一个缓冲区并检查重叠是否可以直接memcpy
; 答案 0 :(得分:4)
事实上。 “好像”意味着它必须表现得像它所做的那样;但并不限制实现实际做到这一点。唯一需要的行为是目标缓冲区以源缓冲区中的正确字节结束,无论缓冲区是否重叠。
一个常见的实现是,如果目标在源之前开始,则从缓冲区的开头向前复制字节,否则从末尾向后复制。这可以确保源字节在被覆盖之前始终被读取,如果存在重叠。
除非分配失败,否则没有错误。低效率是分配和释放临时缓冲区,并将每个字节复制两次而不是一次。
答案 1 :(得分:3)
你绝对是正确的#1 - 描述是为了帮助用户可视化逻辑上的内容,而不是解释它是如何实现的。
但是,没有理智的实现实际上会使用昂贵的临时缓冲区来实现它,因为您需要做的就是避免双重复制是决定是从头开始还是从头开始复制。这是一个sample implementation就是这样做的。
你的算法唯一的问题是它可以在没有必要的情况下运行你的系统内存:想象你的程序试图移动一个大小为允许总内存的60%的缓冲区来查看它的时间示例会发生。
答案 2 :(得分:2)
首先想到的优化机会之一是,如果缓冲区不重叠,则执行简单的memcpy()。由于(虚拟)地址空间的扁平性,因此很容易检查。我查看了glibc和Android实现,并且都执行了此操作(对于初学者来说,Android更容易理解)。
在堆上分配内存可能是不行的,因为它会非常慢(动态分配并不便宜)。
如果缓冲区确实重叠,我们可以优化不复制的部分的复制,对于其余部分我们可能会使用一个小的暂存缓冲区,但如果确实需要任何分配,那将是堆栈分配的。 Android一次只复制一个字节;我们可以在amd64上做得更好,但这与memcpy中已经完成的那种优化相同。 glibc可以向前或向后复制,具体取决于重叠的性质(这是源中“BWD”所指的)。
答案 3 :(得分:1)
实施无关紧要。措辞是为了保证记忆得到妥善处理。
char buf[] = { 0x11, 0x22, 0x33, 0x00 };
memcpy(buf, buf + 1, 3);
可能导致buf
成为{ 0x11, 0x11, 0x11, 0x11 }
。
其中
char buf[] = { 0x11, 0x22, 0x33, 0x00 };
memmove(buf, buf + 1, 3);
保证buf
为{ 0x11, 0x11, 0x22, 0x33 }
。