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

上传人:b****6 文档编号:8853646 上传时间:2023-02-02 格式:DOCX 页数:15 大小:90.04KB
下载 相关 举报
C语言函数strlen源码剖析doc.docx_第1页
第1页 / 共15页
C语言函数strlen源码剖析doc.docx_第2页
第2页 / 共15页
C语言函数strlen源码剖析doc.docx_第3页
第3页 / 共15页
C语言函数strlen源码剖析doc.docx_第4页
第4页 / 共15页
C语言函数strlen源码剖析doc.docx_第5页
第5页 / 共15页
点击查看更多>>
下载资源
资源描述

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

《C语言函数strlen源码剖析doc.docx》由会员分享,可在线阅读,更多相关《C语言函数strlen源码剖析doc.docx(15页珍藏版)》请在冰豆网上搜索。

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

C语言函数strlen源码剖析doc

C语言函数strlen源码剖析

发布日期:

2009-04-06来源:

互联网作者:

佚名

strlen源码剖析

学习高效编程的有效途径之一就是阅读高手写的源代码,CRT(C/C++RuntimeLibrary)作为底层的函数库,实现必然高效。

恰好手中就有glibc和VC的CRT源代码,于是挑了一个相对简单的函数strlen研究了一下,并对各种实现作了简单的效率测试。

strlen的函数原形如下:

size_tstrlen(constchar*str);

strlen返冋str屮字符的个数,其屮str为一个以‘\0‘结尾的字符串(anull-terminatedstring)o

1.简单实现

如果不管效率,最简单的实现只需要4行代码:

1size_tstrlen_a(constchar*str){

size_tlength=0;

3while(*str++)

4++length;

5returnlength;

6}

也许可以稍加改进如下:

1size_tstrlen_b(constchar*str){

2constchar*cp=str;

while(*cp++)

4;

5return(cp一str-1);

6}

2.高效实现

很显然,标准库的实现肯定不会如此简单,上面的strlen_a以及strlen_b都是一次判断一个字符直到发现VT为止,这是非常低效的。

比较高效的实现如卞(在这里WORD表示计算机中的一个字,不是WORD类型):

(1)一次判断一个字符直到内存对齐,如果在内存对齐之前就遇到W则直接return,否则到

(2);

(2)一次读入并判断一个WORD,如果此WORD屮没有为0的字节,则继续下一个WORD,否则到(3);

(3)到这里则说明WORD屮至少有一个字节为0,剩下的就是找出第一个为0的字节的位置然后returno

NOTE:

数据对齐(dataalignment).是指数据所在的内存地址必须是该数据长度的整数倍,这样CPU的存取速度最快。

比如在32位的计算机中,一个WORD为4byte,则WORD数据的起始地址能被4整除的时候CPU的存取效率比较高。

CPU的优化规则人概如下:

对于n字节(n=2,4,8...)的元素,它的首地址能被n整除才能获得最好的性能。

为了便于下面的讨论,这里假设所用的计算机为32位,即一个WORD为4个字节。

下面给出在32位计算机上的C语言实现(假设unsignedlong为4个字节):

1typedefunsignedlongulong;

3size_tstrlen_c(constchar*str){

4

4constchar*char_ptr;

5constalong*longword_ptr;

registerulonglongword,magic_bits;

8

9for(char_ptr=str;((ulong)char_ptr

10

&

(sizeof(ulong)一1))

!

=0;

11

++

char_ptr){

12

if

(*char_ptr==1\01)

i

13

returnchar_ptr一

str;

14

}

15

16longword_ptr=(ulong*)char_ptr;

17

17magic_bits=0x7efefeffL;

19

18while

(1){

21

19longword=*longword_ptr++;

23

20

-magic_bits)

if((((longword+magic_bits)八-longword)

26

constchar*cp

=(constchar*)(longword_ptr-1);

27

28

if

(cp[0]:

==0

29

return

cp_

str;

30

if

(cp[l):

==0

31

return

cp-

str+

1

■f

32

if

(cp[2):

==0

33

return

cp-

str+

2

■f

34

if

(cp[3):

==0

35

return

cp_

str+

3

■f

36

}

37

}

38}

3.源码剖析

上面给出的C语言实现虽然不算特别复杂,但也值得花点时间來弄清楚,先看9・14行:

for(char_ptr=str;((ulong)char_ptr&(sizeof(ulong)-1))!

=0;++

char_ptr){

if(*char_ptr==1\01)

:

returnchar_ptr一str;

}

上面的代码实现了数据对齐,如果在对齐之前就遇到VT则nJ以直接returnchar_ptr・str;

第16行将longword_ptr指向数据对齐后的首地址

longword_ptr=(along*)char_ptr;

第18行给magic_bits赋值(在丿•面会解释这个值的意义)

magic_bits=0x7efefeffL;

第22行读入一个WORD到longword并将longword_ptr指向下一个WORD

longword=*longword_ptr++;

第24行的if语句是整个算法的核心,该语句判断22行读入的WORD中是否有为0的字节if((((longword+magic_bits)A-longword)&~m4gic_bits)!

=0)

if语句中的计算对以分为如下3步:

(1)longword+magic一bits

其中magic_bits的二进制表示如下:

b3b2blb0

31>0

magic_bits:

01111110111111101111111011111111

magic_bits中的31,24,16,8这些bits都为0,我们把这儿个bits称为holes,注意在每个byte的左边都有一个hole。

检测0字节:

如果longword中有一个字节的所有bit都为0,则进行加法后,从这个字节的右边的字节传递来的进位都会落到这个字节的最低位所在的hole上,而从这个字节的最高位则永远不会产生向左边字节的hole的进位。

则这个字节左边的hole在进行加法后不会改变,由此可以检测出0字节;相反,如果longword中所有字节都不为0,则每个字节中至少有1位为1,进行加法后所有的hole都会被改变。

为了便于理解,请看下面的例子:

b3b2blb0

31>0

longword:

XXXXXXXXXXXXXXXX00000000XXXXXXXX

+magic_bits:

01111110111111101111111011111111

上面longword'P的b1为0,X可能为0也可能为1。

因为b1的所有bit都为0,而从b0传递过来的进位只可能是0或1,很显然b1永远也不会产生进位,所以加法后longword的第16bit这个hole不会变。

(2)ATongword

这一步取出加法后longword中所有未改变的bit。

(3)&~magic_bits

最后取出longword中未改变的hole,如果有任何hole未改变则说明longword中有为0的字节。

根据上面的描述,如果longword中有为0的字节,则if中的表达式结果为非0,否则为0。

NOTE:

如果b3为10000000,则进行加法后第31bit这个hole不会变,这说明我们无法检测出b3

为10000000的所有WORD。

值得庆幸的是用于strlen的字符串都是ASCII标准字符,其值在0-127Z间,这意味着每一个字节的第一个bit都为0。

因此上面的算法是安全的。

一旦检测出longword屮有为0的字节,后面的代码只需要找到第一个为0的字节并返回相应的长度就0K:

constchar*cp=(constchar*)(longword_ptr一1);

if

(cp[0]==0)

returncp一

str;

if

(cp[l]=

==0)

return

cp-

str+

1;

if

(cp[2]=

==0)

return

cp-

str+

2;

if

(cp[3]=

==0)

return

cp-

str+

3;

4.另一种实现

1size_tstrlen_d(constchar*str){

2

constchar*char_ptr;

4constulong*longword_ptr;

5registerulonglongword,himagic,lomagic;

6

for(char_ptr=str;((ulong)char_ptr

8&(sizeof(ulong)-1))!

=0;

9++char_ptr){

10if(*char_ptr==*\0*)

11returnchar_ptr一str;

12}

13

longword_ptr=(ulong*)char_ptr;

himagic=0x80808080L;

lomagic=OxOlOlOlOlL;

while

(1){

longword=*longword_ptr++;

24

25constchar*cp=(constchar*)(longword_pti?

-1);

26

27

if

(cp[0]=

==0)

28

return

cp一str;

29

if

(cp[l]=

==0)

30

return

cp一str+1;

31

if

(cp[2]=

==0)

32

return

cp一str+2;

33

if

(cp[3]:

==0)

34

return

cp一str+3;

35}

36}

37}

上面的代码与strlen_c基本一样,不同的是:

magic_bits换成了himagic和lomagic

himagic=0x80808080L;

lomagic=OxOlOlOlOlL;

以及if语句变得比较简单了

if(((longword一lomagic)&himagic)!

=0)

if语句中的计算可以分为如下2步:

(1)Iongword-lomagic

himagic和lomagic的二进制表示如I、•:

k>3b2blb0

31>0

himagic:

10000000100000001000000010000000

lomagic:

00000001000000010000000100000001

在这种方法中假设所有字符都是ASCII标准字符,其值在0・127之间,因此longword总是如下形式:

b3b2blbO

31>0

longword:

OXXXXXXXOXXXXXXXOXXXXXXXOXXXXXXX

检测0字节:

如果longword屮有一个字节的所有bit都为0,则进行减法后,这个字节的最高位一定会从0变为相反,如果longword中所有字节都不为0,则每个字节中至少有1位为1,进行减法后这个字节的最高位依然为0a

(2)&himagic

这一步取出每个字节最高位的1,如果有任意字节最高位为1则说明longword中有为0的字节。

根据上面的描述,如果longword中有为0的字节,则if中的表达式结果为非0,否则为0。

5.汇编实现

VCCRT的汇编实现与前面strlen_c算法类似

1page,132

2titlestrlen一returnthelengthofanull-terminateds

tring

3•***

4;strlen.asm一containsstrlen()routine

5;

6;Copyright(c)MicrosoftCorporation.Allrightsreserved.

7;

8;Purpose:

9;strlenreturnsthelengthofanull-terminatedstring,

10;notincludingthenullbyteitself.

11;

12;****************************************************************

***************

13

13・xlist

14includecruntime・inc

15.list

17

16page

「9.**★

20;strlen一returnthelengthofanull-terminatedstring

25

28

30

33

35

36

1nullbyte

42

45

47

Findsthelengthinbytesofthegivenstring,notinclud

'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k'k

★★★★★★★★★★★★★★★

49

50CODESEG

51

51publicstrlen

53

52strlenproc\

53buf:

ptrbyte

56

54OPTIONPROLOGUE:

NONE,EPILOGUE:

NONE

60

61string

equ

[esp+4]

62

63

mov

ecxfstring

;ecx->string

64

test

ecx,3

;testifstringisalign

59

•FPO

(0,1,0,0,0,0)

edon32bits

65

je

shortmain_loop

66

67

str_misaligned:

68

;simple

?

byteloopuntilstring

isaligned

69

mov

al,byteptr[ecx]

70

add

ecx,1

71

test

al,al

72

je

shortbyte_3

73

test

ecx,3

74

jne

shortstr_misaligned

75

76

add

eax,dwordptr0

;5bytenoptoalign丄4b

elbelow

77

78

align

16

■/

shouldberedundant

79

80

main_loop:

81

mov

eaxzdwordptr[ecx]

•f

read

4bytes

82

mov

edx,7efefeffh

83

add

edx,eax

84

xor

eax,-1

85

xor

eax,edx

86

add

ecx,4

87

test

eaxf81010100h

88

je

shortmain_loop

89

;found

zerobyteintheloop

90

mov

eax,[ecx一4]

91

test

alzal

•f

isit

byte0

92

je

shortbyte_0

93

test

ah,ah

•f

isit

byte1

94

je

shortbyte_l

95

test

eax,OOffOOOOh

•f

isit

byte2

96

je

shortbyte_2

97

test

eax,OffOOOOOOh

98

je

shortbyte_3

99

jmp

shortmain_loop

eclearandbit

100

101

102

byte_3:

103

lea

eax,[ecx-1]

104

mov

ecx,string

105

sub

eax,ecx

106

ret

107

byte_2:

108

lea

eax,[ecx一2]

109

mov

ecx,string

110

sub

eaxzecx

111

:

ret

112

byte_l:

113

lea

eax,[ecx一3]

114

mov

ecx,string

115

sub

eax,ecx

116

ret

117

byte_0:

118

lea

eax,[ecx一4]

119

mov

ecx,string

120

sub

eax,ecx

121

ret

122

123

strlenendp

124

125

end

;isitbyte3

takenifbits24-30ar

31isset

6.测试结果

为了对上述各种实现的效率有一个大概的认识,我在VC8和GCC下分别进行了测试,测试时均采用默认优化方式。

下面是在GCC下运行儿百万次后的结果(在VC8下的运行结果与此相似):

strlen_a

1:

515ticks0・515seconds

 

2:

375

ticks

0.375

seconds

3:

375

ticks

0.375

seconds

4:

375

ticks

0.375

seconds

5:

375

ticks

0.375

seconds

total:

2015

ticks

2.015

seconds

average:

403

ticks

0.403

seconds

 

strlen_b

1:

360

ticks

0.36

seconds

2:

390

ticks

0.39

seconds

3:

375

ticks

0.375

seconds

4:

360

ticks

0.36

seconds

5:

375

ticks

0.375

seconds

total:

1860

ticks

1・86

seconds

average:

372

ticks

0.372

seconds

 

strlen_c

1:

187

ticks

0.187

seconds

2:

172

ticks

0.172

seconds

3:

187

ticks

0.187

seconds

4:

187

ticks

0.187

seconds

5:

188

ticks

0.188

seconds

total:

921

ticks

0.921

seconds

average:

184

ticks

0.1842

seconds

 

strlen_d

1:

172

ticks

0.172

seconds

2:

187

ticks

0.187

seconds

3:

172

ticks

0.172

seconds

4:

187

ticks

0.187

seconds

5:

188

ticks

0.188

seconds

tOtdl:

906

ticks

0.906

seconds

average:

181

ticks

0.1812

seconds

strlen

1:

187

ticks

0.187

seconds

2:

172

ticks

0.172

seconds

3:

188

ticks

0.188

seconds

4:

172

ticks

0.172

seconds

5:

187

ticks

0.187

seconds

total:

906

ticks

0.906

seconds

average:

181

ticks

0.1812

seconds

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 经管营销 > 企业管理

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

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