使用Aztec线性系统求解器库时,我遇到了奇怪的行为。使用valgrind,我发现这个库在重叠缓冲区上执行memcpy
。规范说明memcpy
对重叠缓冲区的行为没有定义。
事实证明,许多机器上的memcpy
具有与使用for循环执行此操作相同的行为,因此您可以安全地从较高的源复制到较低的目标:
for(int i = 0; i < len; i ++)
dest[i] = source[i];
但是在我们的大型集群上,重叠缓冲区的memcpy
具有不同的行为,从而导致出现问题。
现在我想知道库中的重叠memcpy
是正常的还是仅仅是由我的代码中的另一个错误引起的。由于库被广泛使用,我认为应该早先发现memcpy
问题。另一方面,绝大多数memcpy
实现仍然可能像for循环一样,因此没有人遇到过这个问题。
memcpy
的经历吗?memcpy
?我想指出的问题是关于各种实现的实践经验,而不是规范所说的内容。
答案 0 :(得分:13)
我过去曾对此做过一些研究......在Linux上,直到最近,memcpy()
的实施工作方式与memmove()
类似。重叠内存不是一个问题,根据我的经验,其他UNIX是相同的。根据标准,这并没有改变这是未定义的行为这一事实,你很幸运,在某些平台上它有时会起作用 - memmove()
是标准支持的正确答案。
然而,在2010年,glibc维护者推出了一个新的,优化的memcpy()
,它改变了memcpy()
对于某些英特尔核心类型的行为,其中C标准库编译得更快,但没有较长的作品如memmove()
[1]。 (我似乎还记得,这是仅针对大于80字节的内存段触发的新代码)。有趣的是,这导致了像Adobe的Flash版本的Linux版本[2]以及其他几个开源软件包(早在2010年Fedora Linux成为第一个采用更改后的{{1}在glibc)。
答案 1 :(得分:12)
memcpy()
不支持重叠内存。这允许在缓冲区重叠时不起作用的优化。
然而,没有什么可以真正研究的,因为C提供了 支持重叠内存的替代方案:memmove()
。其用法与memcpy()
相同。如果区域可能重叠,您应该使用它,因为它可以解释这种可能性。
答案 2 :(得分:0)