免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
1234下一页
最近访问板块 发新帖
查看: 29020 | 回复: 33
打印 上一主题 下一主题

memcpy vs strcpy vs strlen [复制链接]

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-08-05 21:21 |只看该作者 |倒序浏览
------  理论篇

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次之后的综合)结果。

论坛徽章:
0
2 [报告]
发表于 2010-08-05 21:33 |只看该作者
總結貼迅速占位圍觀{:3_193:}

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
3 [报告]
发表于 2010-08-05 21:39 |只看该作者
寫複雜了, 根本沒必要扯上strlen……

真正的總結版本:

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

论坛徽章:
0
4 [报告]
发表于 2010-08-05 21:52 |只看该作者
google code search上找的strcpy貌似大都是直接逐字節操作的,沒看到的0byte檢測的
具體較快的0byte檢測怎麽弄,給個關鍵字啥的,謝謝{:3_196:}

论坛徽章:
0
5 [报告]
发表于 2010-08-05 21:58 |只看该作者
说着说着都变繁体字了,2分走人

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
6 [报告]
发表于 2010-08-05 22:06 |只看该作者
回复 4# daybreakcx

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

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

论坛徽章:
0
7 [报告]
发表于 2010-08-05 22:11 |只看该作者
回复 6# OwnWaterloo


    多謝提供網址,好好研究一下{:3_203:}

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
8 [报告]
发表于 2010-08-05 22:17 |只看该作者
回复 7# daybreakcx

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

研究完了发发心得啊

论坛徽章:
0
9 [报告]
发表于 2010-08-05 22:18 |只看该作者
回复 8# OwnWaterloo

收了,反正最近有空,慢慢看{:2_168:}

论坛徽章:
0
10 [报告]
发表于 2010-08-05 22:39 |只看该作者
------  理论篇

1. 逐byte

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



    学习了.
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP