+ -
当前位置:首页 → 问答吧 → memcpy vs strcpy vs strlen

memcpy vs strcpy vs strlen

时间:2010-08-05

来源:互联网

------  理论篇

1. 逐byte

如果是C代码编写的最verbose版本:
  1. void* memcpy(void* dst, void const* src, size_t n) {
  2.       char *d=dst, *s=src;
  3.       for (;--n; *d++=*s++);
  4.       return dst;
  5. }

  6. char* strcpy(char* dst, char const* src) {
  7.       char* d=dst;
  8.       while (*d++=*src++);
  9.       return dst;
  10. }

  11. size_t strlen(char const* s) {
  12.       char const* p=s;
  13.       while (*p++);
  14.       return p-s-1;
  15. }
复制代码
那不会相差太多。
需要注意的是, gcc -O2和-O3生成的memcpy的代码会很不相同(下面会解释)
具体是什么-O3中的哪个选项触发的这个优化我就不知道了……

2. 多byte

一些memcpy, strcpy, strlen都不是像上面那样逐byte复制或比较, 而是尽可能一次比较一个机器字。
若要按机器字复制, 就需要考虑对齐问题; strxxx还需要考虑0检测问题。

2.1 memcpy

例如memcpy, 若有适当的对齐, 就可以按int32或者int64复制。
gcc -O3 memcpy就会生成: "对齐检测 -> 按适当对齐复制" 的代码, 而不是单纯的逐byte复制。

有适当对齐下: gcc中用int64会比int32更快一些, msvc两者差不多。

2.2 strcpy

strcpy也首先需要计算一个合适的对齐, 然后按最适合的数据类型复制。
它比memcpy要多考虑的一个问题就是0byte检测。

它慢(源代码实现)也慢在这个地方。
memcpy有长度, 所以可以准确知道循环次数。
strcpy没有长度, 0byte检测虽然有较高效的bit算法, 但还是不如和counter比较来得快。

2.3 合适的对齐

memcpy和strcpy需要计算dst和src最合适的复制类型。

例如: dst=16, src=64。
那么两者可以按1、2、4、8、16字节复制。
可以根据平台上的特点, 选择合适的数据类型(比如32位平台上也许没有16字节的整数类型, 8字节不一定比4字节快)

dst=17, src=65, 那么首先复制1个byte, 然后按上面处理。
dst=18, src=66, 那么前2个byte可以一次复制2byte或者复制2次1byte, 看哪个快, 然后按上面处理。

所以, 在最差的情况下, memcpy和strcpy都只能按byte复制, 例如 dst=x, src=x+2^n-1。

而strlen和它们不同的是, strlen只需要考虑一个串的对齐。
在长度足够的情况下, strlen总是可以将两头单独处理, 中间按最高效的整数类型检测。


------ 实际篇

实际情况是:
在i386下, 逐机器字比逐byte快。
即使没有对齐(i386可以处理整数未对齐)速度会降低, 但还是比byte快。

而且i386上有串复制指令。

所以, 比较它们的效率的时候, 需要注意的问题之一就是:

0. 比较libc的版本, 而不是C写的版本。

另外一些问题:

1. 加入对长串的比较

短串可能赚不回处理零碎部分带来的损失。

2. 比较misalignment的情况

这个其实很简单, malloc返回的是对齐的。
dst=malloc( ... );
src=malloc( ... );
xxxcpy(dst+1, src, ... );
就会让xxxcpy很痛苦。

3. 检测cache情况

有些malloc(甚至calloc)的实现在实际访问内存前, 是不会分配物理内存的。
所以, 对先被测试的函数来说总是不公平的, 它会引发多得多的页错误。
比较的不是memcpy和strcpy的比较, 而是它们和页置换算法+memcpy的比较。

可以考虑将相同的动作执行连续执行2(多)次, 取后一次(第2次之后的综合)结果。

作者: OwnWaterloo   发布时间: 2010-08-05

總結貼迅速占位圍觀

作者: daybreakcx   发布时间: 2010-08-05

寫複雜了, 根本沒必要扯上strlen……

真正的總結版本:

1. 一次性複製多個byte可能會比逐byte複製快
2. 一次複製多個byte, 會造成檢測結束條件變化
3. memcpy依然是檢測counter, strcpy就需要檢測word中是否含有0byte —— 差異
4. 兩者可能都不是由C實現的, i386上, memcpy受的照顧比strcpy要多。

作者: OwnWaterloo   发布时间: 2010-08-05

google code search上找的strcpy貌似大都是直接逐字節操作的,沒看到的0byte檢測的
具體較快的0byte檢測怎麽弄,給個關鍵字啥的,謝謝

作者: daybreakcx   发布时间: 2010-08-05

说着说着都变繁体字了,2分走人

作者: zhangsuozhu   发布时间: 2010-08-05

回复 daybreakcx

strcpy需要同时考虑dst, src的对齐, 比strlen复杂, 可能使用的不多。

0byte的这里有一个:
http://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord

作者: OwnWaterloo   发布时间: 2010-08-05

回复 OwnWaterloo


    多謝提供網址,好好研究一下

作者: daybreakcx   发布时间: 2010-08-05

回复 daybreakcx

感兴趣的话, 这里还有2个……
http://www.hackersdelight.org/HDcode.htm
http://aggregate.org/MAGIC/

研究完了发发心得啊

作者: OwnWaterloo   发布时间: 2010-08-05

回复 OwnWaterloo

收了,反正最近有空,慢慢看

作者: daybreakcx   发布时间: 2010-08-05



QUOTE:
------  理论篇

1. 逐byte

如果是C代码编写的最verbose版本:那不会相差太多。
需要注意的是, gcc  ...
OwnWaterloo 发表于 2010-08-05 21:21




    学习了.

作者: bluesea666   发布时间: 2010-08-05