【发布时间】:2022-01-20 22:03:10
【问题描述】:
cpu(基准方式)复制字符串最有效的方式是什么?
我是 c 新手,我目前正在复制这样的字符串
char a[]="copy me";
char b[sizeof(a)];
for (size_t i = 0; i < sizeof(a); i++) {
b[i] = a[i];
}
printf("%s",b); // copy me
这是另一种选择,while 循环比 for 循环快一点(我听说过的)
char a[]="copy me";
char b[sizeof(a)];
char c[sizeof(a)];
void copyAString (char *s, char *t)
{
while ( (*s++ = *t++) != '\0');
};
copyAString(b,a);
printf("%s",c);
【问题讨论】:
-
对于编译时常数大小,几乎总是
memcpy。当以较小的固定大小调用时,编译器将内联它。当然,优化编译器也将识别此复制循环并将其替换为对 memcpy 的实际调用或它的内联扩展,无论您如何进行数组索引。不过,这个例子太小太简单,实际上不能用作基准。 Idiomatic way of performance evaluation? -
re:您的编辑:第二种方式是
strcpy用于隐式长度字符串。这比较慢,因为它必须搜索终止的 0 字节,如果在内联和展开循环后编译时不知道它。 (如果幸运的话,它将优化循环以调用 libc 中的strcpy,它使用手写 asm 来高效地执行此操作,尤其是在 SIMD 可以提供帮助的 x86 等 ISA 上。) -
while 循环与 for 循环的效率属于“沉没成本”类别——节省的成本不会随字符串长度而变化。正如 Peter Cordes 所说,memcpy() 很难改进,但很有可能您的编译器会在可能的地方使用它(即使您没有明确调用它)。但是,如果您确实直接调用 memcpy(),请确保包含空终止符。
-
@mzimmers:作为数组初始值设定项的字符串文字确实包含终止 0 字节。而
sizeof()是数组的整个大小,包括它。所以char a[]="copy me";的第一个示例确实复制了终止符,就像 strcpy 版本一样。 -
@PeterCordes:没有争论。我并没有特别提到这个例子。只是在字符串上使用 memcpy 时需要记住的一件事。
标签: c string loops for-loop benchmarking