2011-10-13 48 views

回答

5

只要没有任何不愉快的发生在相对于填充位或严格别名规则的,并假设类型的大小是按预期,和条件是所述存储器区域不重叠,并且被正确地对准,则它们每一从一个地方复制8个字节到另一个地方。

当然,除了实际效果有可能在性能和/或代码大小的差。

如果你看到的东西休息,然后看所发出的实际代码,这可能会告诉你出了什么问题。除非你有很多优化开启,甚至可能进行优化,否则我不会立即明白为什么这些优化不会与AMD64,Ubuntu和gcc相当。

事情我已经提到,可能会出错:

  • 填充比特 - 并不适用于GCC,但标准允许unsignedunsigned long有填充位,如果这样的话有可能是位它们是一个或两个陷阱表示的模式,只要您解除引用就可能爆炸。
  • 严格别名 - 不太可能影响该代码的功能,但可能会影响用于检查结果的代码。例如,如果sd是转换指针到双到uint8_t*的结果,你看看所产生的双,然后在一个或这两种情况下,你可能看不到变化的影响,因为你有一个非法的类型 - 双关语。该类型的
  • 尺寸 - 因为64位Linux是LP64,但很明显,如果sizeof(long) == 4那么这两个是不等价不应适用于此。 long在64位Windows系统上是32位,而不是64位Linux系统。
  • 重叠 - 如果d == s + 4,那么这两个代码片段有不同的效果。因此,除非编译器知道ds指向完全不同的地方(这就是C99 restrict的用途),否则不会看到第一个优化成为第二个优化。
  • 对齐 - 我不记得x86-64的对齐要求是什么:对于x86,您可以使用未对齐的读/写功能,但速度较慢。一般来说,如果sd正确对齐int而不是long那么就有区别。 (编辑:显然你可以启用或禁用x86-64上未对齐访问的硬件异常)。
1

如果需要精确地复制一个八字节,为什么不使用的memcpy()?

memcpy(d, s, 8); 

使用GCC,它会散发出内嵌代码,而不是调用库函数,所以它应该是为你的手写入内存复制速度更快。

加奖金,你的代码将在ILP32系统工作,LP64(64位大部分的Unix)和LLP64(Win64的),甚至与严格对齐要求的系统。

+1

“它应该像你手写的内存拷贝一样快 - ”在类似x86的架构上可能是真的。在像ARM,虽然,这确实有严格的对准要求,该版本与石膏可以使用需要对齐的访问速度更快的操作码,而'memcpy'必须要么使用速度较慢的操作码,与未对齐指针的应对,或者至少进行一些检查在使用快速之前。无论哪种方式,'memcpy'都会增加一些额外的开销,但是当然如您所说,如果'd'和's'事实上没有正确对齐,则使用强制转换的版本不起作用。 –

1

如果性能并不重要,你应该只使用memcpy()作为另一个答案。

如果到*s写入后不久出现这种代码,匹配类型;如果此代码在从*d读取之前发生,请匹配类型。这将确保从存储到加载转发(将数据从存储直接转移到加载,而无需等待存储将数据写回到数据高速缓存中)可以在尽可能多的CPU上工作。如果存储和加载的地址和大小匹配并保持一致,则存储到加载转发几乎总是有效的,并且根据CPU可能会更频繁地运行。如果存储到加载转发失败,惩罚倾向于大约10个时钟周期。

如果您可以通过添加额外的移位/和/或操作避免储存至加载转送的问题,这往往要快。

如果您更有效地用C的类型系统,避免石膏,将可避免许多存储至加载转送的问题。

相关问题