ImageVerifierCode 换一换
格式:DOCX , 页数:15 ,大小:90.04KB ,
资源ID:8853646      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/8853646.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(C语言函数strlen源码剖析doc.docx)为本站会员(b****6)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

C语言函数strlen源码剖析doc.docx

1、C语言函数strlen源码剖析docC语言函数strlen源码剖析发布日期:2009-04-06来源:互联网 作者:佚名strlen源码剖析学习高效编程的有效途径之一就是阅读高手写的源代码,CRT(C/C+ Runtime Library)作为 底层的函数库,实现必然高效。恰好手中就有glibc和VC的CRT源代码,于是挑了一个相 对简单的函数strlen研究了一下,并对各种实现作了简单的效率测试。strlen的函数原形如下:size_t strlen (const char *str);strlen返冋str屮字符的个数,其屮str为一个以0结尾的字符串(a null-terminated

2、string)o1. 简单实现如果不管效率,最简单的实现只需要4行代码:1 size_t strlen_a(const char * str) size_t length = 0 ;3 while (*str+ )4 + length;5 return length;6 也许可以稍加改进如下:1 size_t strlen_b(const char * str) 2 const char *cp = str;while (*cp+ )4 ;5 return (cp 一 str - 1 );6 2. 高效实现很显然,标准库的实现肯定不会如此简单,上面的strlen_a以及strlen_b都是一次

3、判断一 个字符直到发现VT为止,这是非常低效的。比较高效的实现如卞(在这里WORD表示计算 机中的一个字,不是WORD类型):(1) 一次判断一个字符直到内存对齐,如果在内存对齐之前就遇到W则直接return,否则到(2) ;(2) 一次读入并判断一个WORD,如果此WORD屮没有为0的字节,则继续下一个WORD, 否则到(3);(3) 到这里则说明WORD屮至少有一个字节为0,剩下的就是找出第一个为0的字节的位 置然后return oNOTE:数据对齐(data alignment).是指数据所在的内存地址必须是该数据长度的整数倍,这样CPU 的存取速度最快。比如在32位的计算机中,一个WO

4、RD为4 byte,则WORD数据的起始 地址能被4整除的时候CPU的存取效率比较高。CPU的优化规则人概如下:对于n字节(n =2,4,8.)的元素,它的首地址能被n整除才能获得最好的性能。为了便于下面的讨论,这里假设所用的计算机为32位,即一个WORD为4个字节。下面 给出在32位计算机上的C语言实现(假设unsigned long为4个字节):1 typedef unsigned long ulong;3 size_t strlen_c (const char * str) 44 const char * char_ptr;5 const along * longword_ptr;reg

5、ister ulong longword, magic_bits;89 for (char_ptr = str; (ulong)char_ptr10&(sizeof (ulong) 一 1)!= 0 ;11+char_p tr) 12if(*char_ptr = 101 )i13return char_ptr 一str;141516 longword_ptr = (ulong* )char_ptr;1717 magic_bits = 0x7efefeffL ;1918 while (1 ) 2119 longword = *longword_ptr+ ;2320 -magic_bits)if

6、( ( ( (longword + magic_bits) 八 -longword)26const char *cp= (const char*) (longword_ptr - 1 );2728if(cp0:=0)29returncp _str;30if(cpl):=0)31returncp -str +1 f32if(cp2):=0)33returncp -str +2 f34if(cp3):=0)35returncp _str +3 f363738 3.源码剖析上面给出的C语言实现虽然不算特别复杂,但也值得花点时间來弄清楚,先看914行:for (char_ptr = str; ( (u

7、long) char_ptr & (sizeof (ulong) - 1) ) ! = 0; +char_ptr) if (*char_ptr = 101):return char_ptr 一 str;上面的代码实现了数据对齐,如果在对齐之前就遇到VT则nJ以直接return char_ptrstr;第16行将longword_ptr指向数据对齐后的首地址longword_ptr = (along*)char_ptr;第18行给magic_bits赋值(在丿面会解释这个值的意义)magic_bits = 0x7efefeffL;第22行读入一个WORD到longword并将longword_p

8、tr指向下一个WORDlongword = *longword_ptr+;第24行的if语句是整个算法的核心,该语句判断22行读入的WORD中是否有为0的字节 if (longword + magic_bits) A -longword) & m4gic_bits) != 0)if语句中的计算对以分为如下3步:(1) longword + magic一bits其中magic_bits的二进制表示如下:b3 b2 bl b031 0magic_bits: 01111110 11111110 11111110 11111111magic_bits中的31,24,16,8这些bits都为0,我们把这

9、儿个bits称为holes,注意在每个 byte的左边都有一个hole。检测0字节:如果longword中有一个字节的所有bit都为0,则进行加法后,从这个字节的右边的字节 传递来的进位都会落到这个字节的最低位所在的hole上,而从这个字节的最高位则永远不 会产生向左边字节的hole的进位。则这个字节左边的hole在进行加法后不会改变,由此可 以检测出0字节;相反,如果longword中所有字节都不为0,则每个字节中至少有1位为 1,进行加法后所有的hole都会被改变。为了便于理解,请看下面的例子:b3 b2 bl b031 0longword: XXXXXXXX XXXXXXXX 00000

10、000 XXXXXXXX+ magic_bits: 01111110 11111110 11111110 11111111上面longword P的b1为0, X可能为0也可能为1。因为b1的所有bit都为0,而从b0 传递过来的进位只可能是0或1,很显然b1永远也不会产生进位,所以加法后longword 的第16 bit这个hole不会变。(2) A Tongword这一步取出加法后longword中所有未改变的bit。(3) & magic_bits最后取出longword中未改变的hole,如果有任何hole未改变则说明longword中有为0的 字节。根据上面的描述,如果longwor

11、d中有为0的字节,则if中的表达式结果为非0,否则为0。NOTE:如果b3为10000000,则进行加法后第31 bit这个hole不会变,这说明我们无法检测出b3为10000000的所有WORD。值得庆幸的是用于strlen的字符串都是ASCII标准字符,其 值在0-127 Z间,这意味着每一个字节的第一个bit都为0。因此上面的算法是安全的。一旦检测出longword屮有为0的字节,后面的代码只需要找到第一个为0的字节并返回相 应的长度就0K:const char *cp = (const char*) (longword_ptr 一 1);if(cp0 = 0)return cp 一st

12、r;if(cpl=0)returncp -str +1;if(cp2=0)returncp -str +2;if(cp3=0)returncp -str +3;4.另一种实现1 size_t strlen_d(const char *str) 2const char *char_ptr;4 const ulong *longword_ptr;5 register ulong longword, himagic, lomagic;6for (char_ptr = str; (ulong)char_ptr8 & (sizeof (ulong) - 1) != 0;9 +char_ptr) 10 i

13、f (*char_ptr = *0 *)11 return char_ptr 一 str;12 13longword_ptr = (ulong*)char_ptr;himagic = 0x80808080L;lomagic = OxOlOlOlOlL;while (1) longword = *longword_ptr+;2425 const char *cp = (const char*) (longword_pti? - 1);2627if(cp0=0)28returncp 一 str;29if(cpl=0)30returncp 一 str + 1;31if(cp2=0)32returnc

14、p 一 str +2;33if(cp3:=0)34returncp 一 str + 3;35 36 37 上面的代码与strlen_c基本一样,不同的是: magic_bits 换成了 himagic 和 lomagichimagic = 0x80808080L;lomagic = OxOlOlOlOlL;以及if语句变得比较简单了if ( ( (longword 一 lomagic) & himagic) ! = 0)if语句中的计算可以分为如下2步:(1) Iongword - lomagichimagic和lomagic的二进制表示如I、:k3 b2 bl b031 0himagic:

15、10000000 10000000 10000000 10000000lomagic: 00000001 00000001 00000001 00000001在这种方法中假设所有字符都是ASCII标准字符,其值在0127之间,因此longword总是 如下形式:b3 b2 bl bO31 0longword: OXXXXXXX OXXXXXXX OXXXXXXX OXXXXXXX检测0字节:如果longword屮有一个字节的所有bit都为0,则进行减法后,这个字节的最高位一定会 从0变为相反,如果longword中所有字节都不为0,则每个字节中至少有1位为1, 进行减法后这个字节的最高位依然为

16、0a(2) & himagic这一步取出每个字节最高位的1,如果有任意字节最高位为1则说明longword中有为0的 字节。根据上面的描述,如果longword中有为0的字节,则if中的表达式结果为非0,否则为0。5.汇编实现VC CRT的汇编实现与前面strlen_c算法类似1 page , 1322 title strlen 一 return the length of a null-terminated st ring3 * * *4 ;strlen.asm 一 contains strlen () routine5 ;6 ; Copyright (c) Microsoft Corpor

17、ation. All rights reserved.7 ;8 ;Purpose:9 ; strlen returns the length of a null-terminated string,10 ; not including the null byte itself.11 ;12 ;*1313 xlist14 include cruntime inc15 .list1716 page9 . * * 20 ;strlen 一 return the length of a null-terminated string2528303335361 null byte424547Finds t

18、he length in bytes of the given string, not includkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk4950 CODESEG5151 public strlen5352 strlen proc 53 buf:ptr byte5654 OPTION PROLOGUE:NONE, EPILOGUE:NONE6061 stringequesp + 46263movecxf string;ecx - string64t estecx, 3;test if string is

19、align59 FPO(0, 1, 0, 0, 0, 0 )ed on 32 bits65jeshort main_loop6667str_misaligned:68;simple? byte loop until stringis aligned69moval,byte ptr ecx70addecx, 171testal, al72jeshort byte_373t estecx, 374jneshort str_misaligned7576addeax,dword ptr 0;5 byte nop to align 丄4bel below7778align16 /should be re

20、dundant7980main_loop:81moveaxz dword ptr ecx fread4 bytes82movedx,7efefeffh83addedx,eax84xoreax,-185xoreax,edx86addecx, 487testeaxf 81010100h88jeshort main_loop89;foundzero byte in the loop90moveax,ecx 一 491testalz al fis itbyte 092jeshort byte_093testah, ah fis itbyte 194jeshort byte_l95testeax,OOf

21、fOOOOh fis itbyte 296jeshort byte_297testeax,OffOOOOOOh98jeshort byte_399jmpshort main_loope clear and bit100101102byte_3:103leaeax,ecx - 1104movecx,string105subeax,ecx106ret107byte_2 :108leaeax,ecx 一 2109movecx,string110subeaxz ecx111:ret112byte_l:113leaeax,ecx 一 3114movecx,string115subeax,ecx116re

22、t117byte_0:118leaeax,ecx 一 4119movecx,string120subeax,ecx121ret122123strlen endp124125end;is it byte 3taken if bits 24-30 ar31 is set6.测试结果为了对上述各种实现的效率有一个大概的认识,我在VC8和GCC下分别进行了测试,测 试时均采用默认优化方式。下面是在GCC下运行儿百万次后的结果(在VC8下的运行结果 与此相似):strlen_a1: 515 ticks 0515 seconds2:375ticks0.375seconds3:375ti cks0.375s

23、econds4:375ticks0.375seconds5:375ti cks0.375secondstotal:2015ticks2.015secondsaverage:403ti cks0.403secondsstrlen_b1:360ticks0.36seconds2:390ti cks0.39seconds3:375ticks0.375seconds4:360ticks0.36seconds5 :375ticks0.375secondstotal:1860ti cks186secondsaverage:372ticks0.372secondsstrlen_c1:187ti cks0.1

24、87seconds2:172ticks0.172seconds3:187ticks0.187seconds4:187ticks0.187seconds5:188ti cks0.188secondstotal:921ticks0.921secondsaverage:184ti cks0.1842secondsstrlen_d1:172ticks0.172seconds2:187ticks0.187seconds3:172ticks0.172seconds4:187ti cks0.187seconds5 :188ticks0.188secondstOtdl:906ti cks0.906secondsaverage:181ticks0.1812secondsstrlen1:187ti cks0.187seconds2:172ticks0.172seconds3:188ti cks0.188seconds4:172ticks0.172seconds5 :187ticks0.187secondstotal:906ticks0.906secondsaverage:181ti cks0.1812seconds

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1