使用memcpy移动缓冲区尾部至头部(内存重叠)是否安全?
嘿,我得先纠正你一个关键的误解——在你这个特定的场景里,memcpy其实完全不会有内存覆盖的风险,不管尾部多大都没问题!
你是把缓冲区的高地址部分(从cur开始的尾部)复制到低地址的头部,也就是源起始地址buf+cur是大于目标起始地址buf的。这种情况下,哪怕两个区域有重叠,memcpy从低到高的复制顺序也不会搞砸:
举个小例子,假设缓冲区是8字节,cur=3,要把buf[3..7]的[3,4,5,6,7]复制到buf[0..4]。memcpy会先把buf[3](3)写到buf[0],然后buf[4](4)写到buf[1]……直到最后把buf[7](7)写到buf[4]。整个过程中,我们要复制的源数据(高地址部分)在被读取之前,都不会被覆盖——因为目标地址始终比当前读取的源地址小,不会提前改写还没用到的源字节。
只有反过来的情况(把低地址数据复制到高地址,且两个区域重叠),memcpy才会出问题。比如你要把buf[0..4]复制到buf[3..7],这时候从低到高复制会先把buf[0]写到buf[3],等后面要读取buf[3]的时候,它已经被改成buf[0]的值了,这才会出错。
所以回到你的问题:不存在“多大尾部算过大”的情况,你当前的memcpy代码在任何尾部长度下都是安全的。
当然,如果你想彻底消除顾虑,或者担心未来代码被修改成其他复制方向,直接把memcpy换成memmove就好——memmove会自动判断重叠情况,必要时从后往前复制,而且对于8192字节这种小缓冲区来说,性能损失几乎可以忽略,现代x86_64编译器对memmove的优化已经做得非常棒了,和memcpy的差异微乎其微。
内容的提问来源于stack exchange,提问作者Lapsio

