青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

posts - 297,  comments - 15,  trackbacks - 0

學(xué)習(xí)高效編程的有效途徑之一就是閱讀高手寫的源代碼,CRT(C/C++ Runtime Library)作為底層的函數(shù)庫,實現(xiàn)必然高效。恰好手中就有g(shù)libc和VC的CRT源代碼,于是挑了一個相對簡單的函數(shù)strlen研究了一下,并對各種實現(xiàn)作了簡單的效率測試。

strlen的函數(shù)原形如下:

      size_t strlen(const char *str);

strlen返回str中字符的個數(shù),其中str為一個以'\0'結(jié)尾的字符串(a null-terminated string)。

1. 簡單實現(xiàn)
如果不管效率,最簡單的實現(xiàn)只需要4行代碼:

1 size_t strlen_a(const char * str) {
2     size_t length = 0
;
3     while (*str++
)
4         ++
length;
5     return
 length;
6 }

也許可以稍加改進(jìn)如下:

1 size_t strlen_b(const char * str) {
2     const char *cp =
 str;
3     while (*cp++
)
4 
        ;
5     return (cp - str - 1
);
6 }

2. 高效實現(xiàn)
很顯然,標(biāo)準(zhǔn)庫的實現(xiàn)肯定不會如此簡單,上面的strlen_a以及strlen_b都是一次判斷一個字符直到發(fā)現(xiàn)'\0'為止,這是非常低效的。比較高效的實現(xiàn)如下(在這里WORD表示計算機(jī)中的一個字,不是WORD類型):
(1) 一次判斷一個字符直到內(nèi)存對齊,如果在內(nèi)存對齊之前就遇到'\0'則直接return,否則到(2);
(2) 一次讀入并判斷一個WORD,如果此WORD中沒有為0的字節(jié),則繼續(xù)下一個WORD,否則到(3);
(3) 到這里則說明WORD中至少有一個字節(jié)為0,剩下的就是找出第一個為0的字節(jié)的位置然后return。


NOTE:
數(shù)據(jù)對齊(data alignment), 是指數(shù)據(jù)所在的內(nèi)存地址必須是該數(shù)據(jù)長度的整數(shù)倍,這樣CPU的存取速度最快。比如在32位的計算機(jī)中,一個WORD為4 byte,則WORD數(shù)據(jù)的起始地址能被4整除的時候CPU的存取效率比較高。CPU的優(yōu)化規(guī)則大概如下:對于n字節(jié)(n = 2,4,8...)的元素,它的首地址能被n整除才能獲得最好的性能。

為了便于下面的討論,這里假設(shè)所用的計算機(jī)為32位,即一個WORD為4個字節(jié)。下面給出在32位計算機(jī)上的C語言實現(xiàn)(假設(shè)unsigned long為4個字節(jié)):

 1 typedef unsigned long  ulong;
 2 

 3 size_t strlen_c(const char * str) {
 4 

 5     const char * char_ptr;
 6     const ulong *
longword_ptr;
 7 
    register ulong longword, magic_bits;
 8 

 9     for (char_ptr =  str; ((ulong)char_ptr 
10         & (sizeof(ulong) - 1)) != 0
;
11         ++
char_ptr) {
12         if (*char_ptr == '\0'
)
13             return char_ptr -
 str;
14 
    }
15 

16     longword_ptr = (ulong* )char_ptr;
17 

18     magic_bits = 0x7efefeffL ;
19 

20     while (1 ) {
21 

22         longword = *longword_ptr++ ;
23 

24         if ((((longword + magic_bits) ^ ~longword) & ~magic_bits) != 0 ) {
25 

26             const char *cp = (const char*)(longword_ptr - 1 );
27 
            
28             if (cp[0== 0
)
29                 return cp -
 str;
30             if (cp[1== 0
)
31                 return cp - str + 1
;
32             if (cp[2== 0
)
33                 return cp - str + 2
;
34             if (cp[3== 0
)
35                 return cp - str + 3
;
36 
        }
37 
    }
38 }

3. 源碼剖析
上面給出的C語言實現(xiàn)雖然不算特別復(fù)雜,但也值得花點時間來弄清楚,先看9-14行:
for (char_ptr = str; ((ulong)char_ptr & (sizeof(ulong) - 1)) != 0++char_ptr) {
    
if (*char_ptr == '\0'
)
        
return char_ptr -
 str;
}

上面的代碼實現(xiàn)了數(shù)據(jù)對齊,如果在對齊之前就遇到'\0'則可以直接return char_ptr - str;

第16行將longword_ptr指向數(shù)據(jù)對齊后的首地址

longword_ptr = (ulong*)char_ptr;

第18行給magic_bits賦值(在后面會解釋這個值的意義)
magic_bits = 0x7efefeffL;

第22行讀入一個WORD到longword并將longword_ptr指向下一個WORD
longword = *longword_ptr++;

第24行的if語句是整個算法的核心,該語句判斷22行讀入的WORD中是否有為0的字節(jié)
if ((((longword + magic_bits) ^ ~longword) & ~magic_bits) != 0)
if語句中的計算可以分為如下3步:
(1) longword + magic_bits
其中magic_bits的二進(jìn)制表示如下:
                  b3      b2       b1       b0
              
31------------------------------->0

  magic_bits: 
01111110 11111110 11111110 11111111
magic_bits中的31,24,16,8這些bits都為0,我們把這幾個bits稱為holes,注意在每個byte的左邊都有一個hole。

檢測0字節(jié):
如 果longword 中有一個字節(jié)的所有bit都為0,則進(jìn)行加法后,從這個字節(jié)的右邊的字節(jié)傳遞來的進(jìn)位都會落到這個字節(jié)的最低位所在的hole上,而從這個字節(jié)的最高位則 永遠(yuǎn)不會產(chǎn)生向左邊字節(jié)的hole的進(jìn)位。則這個字節(jié)左邊的hole在進(jìn)行加法后不會改變,由此可以檢測出0字節(jié);相反,如果longword中所有字節(jié) 都不為0,則每個字節(jié)中至少有1位為1,進(jìn)行加法后所有的hole都會被改變。

為了便于理解,請看下面的例子:
                  b3      b2       b1       b0
              31------------------------------->0
  longword:   XXXXXXXX XXXXXXXX 
00000000 XXXXXXXX
+ magic_bits: 01111110 11111110 11111110 11111111
上面longword中的b1為0,X可能為0也可能為1。因為b1的所有bit都為0,而從b0傳遞過來的進(jìn)位只可能是0或1,很顯然b1永遠(yuǎn)也不會產(chǎn)生進(jìn)位,所以加法后longword的第16 bit這個hole不會變。

(2)  ^ ~longword
這一步取出加法后longword中所有未改變的bit。

(3)  & ~magic_bits
最后取出longword中未改變的hole,如果有任何hole未改變則說明longword中有為0的字節(jié)。

根據(jù)上面的描述,如果longword中有為0的字節(jié),則if中的表達(dá)式結(jié)果為非0,否則為0。
NOTE:
如 果b3為10000000,則進(jìn)行加法后第31 bit這個hole不會變,這說明我們無法檢測出b3為10000000的所有WORD。值得慶幸的是用于strlen的字符串都是ASCII標(biāo)準(zhǔn)字符, 其值在0-127之間,這意味著每一個字節(jié)的第一個bit都為0。因此上面的算法是安全的。

一旦檢測出longword中有為0的字節(jié),后面的代碼只需要找到第一個為0的字節(jié)并返回相應(yīng)的長度就OK:
const char *cp = (const char*)(longword_ptr - 1);

if (cp[0== 0
)
    
return cp -
 str;
if (cp[1== 0
)
    
return cp - str + 1
;
if (cp[2== 0
)
    
return cp - str + 2
;
if (cp[3== 0
)
    
return cp - str + 3;

4. 另一種實現(xiàn)
 1 size_t strlen_d(const char *str) {
 2 

 3     const char *char_ptr;
 4     const ulong *
longword_ptr;
 5 
    register ulong longword, himagic, lomagic;
 6 

 7     for (char_ptr = str; ((ulong)char_ptr 
 8         & (sizeof(ulong) - 1)) != 0
;
 9         ++
char_ptr) {
10         if (*char_ptr == '\0'
)
11             return char_ptr -
 str;
12 
    }
13 

14     longword_ptr = (ulong*)char_ptr;
15 

16     himagic = 0x80808080L;
17     lomagic = 0x01010101L
;
18 

19     while (1) {
20 

21         longword = *longword_ptr++;
22 

23         if (((longword - lomagic) & himagic) != 0) {
24 

25             const char *cp = (const char*)(longword_ptr - 1);
26 
            
27             if (cp[0== 0
)
28                 return cp -
 str;
29             if (cp[1== 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 
= 0x01010101L;
以及 if語句變得比較簡單了
if (((longword - lomagic) & himagic) != 0)

if語句中的計算可以分為如下2步:
(1) longword - lomagic
himagic和lomagic的二進(jìn)制表示如下:
                b3      b2       b1       b0
            
31------------------------------->0

  himagic:  10000000 10000000 
10000000 10000000
  lomagic:  00000001 00000001 00000001 00000001

在這種方法中假設(shè)所有字符都是ASCII標(biāo)準(zhǔn)字符,其值在0-127之間,因此longword總是如下形式:
                b3      b2       b1       b0
            
31------------------------------->0

  longword: 
0XXXXXXX 0XXXXXXX 0XXXXXXX 0XXXXXXX

檢測0字節(jié):
如果longword 中有一個字節(jié)的所有bit都為0,則進(jìn)行減法后,這個字節(jié)的最高位一定會從0變?yōu)?;相反,如果longword中所有字節(jié)都不為0,則每個字節(jié)中至少有1位為1,進(jìn)行減法后這個字節(jié)的最高位依然為0。

 (2)  & himagic
這一步取出每個字節(jié)最高位的1,如果有任意字節(jié)最高位為1則說明longword中有為0的字節(jié)。

根據(jù)上面的描述,如果longword中有為0的字節(jié),則if中的表達(dá)式結(jié)果為非0,否則為0。

5. 匯編實現(xiàn)
VC CRT的匯編實現(xiàn)與前面strlen_c算法類似

  1         page    ,132
  2         title   strlen - return the length of a null-terminated string
  3 ;***

  4 ;strlen.asm - contains strlen() routine
  5 
;
  6 
;       Copyright (c) Microsoft Corporation. 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 ;*******************************************************************************

 13 
 14         .xlist
 15 
        include cruntime.inc
 16 
        .list
 17 

 18 page
 19 ;***

 20 ;strlen - return the length of a null-terminated string
 21 
;
 22 
;Purpose:
 23 
;       Finds the length in bytes of the given string, not including
 24 ;       the final null
 character.
 25 
;
 26 
;       Algorithm:
 27 ;       int strlen (const char *
 str)
 28 
;       {
 29 ;           int length = 0
;
 30 
;
 31 ;           while*str++
 )
 32 ;                   ++
length;
 33 
;
 34 ;           return
( length );
 35 
;       }
 36 
;
 37 
;Entry:
 38 ;       const char * str -
 string whose length is to be computed
 39 
;
 40 
;Exit:
 41 ;       EAX = length of the string "str", exclusive of the final null byte

 42 ;
 43 
;Uses:
 44 
;       EAX, ECX, EDX
 45 
;
 46 
;Exceptions:
 47 
;
 48 ;*******************************************************************************

 49 
 50         CODESEG
 51 

 52         public  strlen
 53 

 54 strlen  proc \
 55         buf:ptr byte

 56 
 57         OPTION PROLOGUE:NONE, EPILOGUE:NONE
 58 

 59         .FPO    ( 010000 )
 60 

 61 string  equ     [esp + 4]
 62 

 63         mov     ecx,string              ; ecx -> string
 64         test    ecx,3                   ; test if string is aligned on 32
 bits
 65         je      short
 main_loop
 66 

 67 str_misaligned:
 68         ; simple byte
 loop until string is aligned
 69         mov     al,byte
 ptr [ecx]
 70         add     ecx,1

 71         test    al,al
 72         je      short
 byte_3
 73         test    ecx,3

 74         jne     short str_misaligned
 75 

 76         add     eax,dword ptr 0         ; 5 byte nop to align label below
 77 

 78         align   16                      ; should be redundant
 79 

 80 main_loop:
 81         mov     eax,dword ptr [ecx]     ; read 4
 bytes
 82 
        mov     edx,7efefeffh
 83 
        add     edx,eax
 84         xor     eax,-1

 85         xor     eax,edx
 86         add     ecx,4

 87         test    eax,81010100h
 88         je      short
 main_loop
 89         ; found zero byte
 in the loop
 90         mov     eax,[ecx - 4
]
 91         test    al,al                   ; is it byte 0

 92         je      short byte_0
 93         test    ah,ah                   ; is it byte 1

 94         je      short byte_1
 95         test    eax,00ff0000h           ; is it byte 2

 96         je      short byte_2
 97         test    eax,0ff000000h          ; is it byte 3

 98         je      short byte_3
 99         jmp     short main_loop         ; taken if bits 24-30
 are clear and bit
100                                         ; 31
 is set
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     eax,ecx
111 
        ret
112 
byte_1:
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 strlen  endp
124 

125         end

6. 測試結(jié)果
為了對上述各種實現(xiàn)的效率有一個大概的認(rèn)識,我在VC8和GCC下分別進(jìn)行了測試,測試時均采用默認(rèn)優(yōu)化方式。下面是在GCC下運行幾百萬次后的結(jié)果(在VC8下的運行結(jié)果與此相似):
strlen_a
--------------------------------------------------

       
1:        515 ticks         0.515 seconds
       
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
   total:        
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
--------------------------------------------------
posted on 2008-07-19 11:33 chatler 閱讀(276) 評論(0)  編輯 收藏 引用 所屬分類: C++_BASIS
<2010年3月>
28123456
78910111213
14151617181920
21222324252627
28293031123
45678910

常用鏈接

留言簿(10)

隨筆分類(307)

隨筆檔案(297)

algorithm

Books_Free_Online

C++

database

Linux

Linux shell

linux socket

misce

  • cloudward
  • 感覺這個博客還是不錯,雖然做的東西和我不大相關(guān),覺得看看還是有好處的

network

OSS

  • Google Android
  • Android is a software stack for mobile devices that includes an operating system, middleware and key applications. This early look at the Android SDK provides the tools and APIs necessary to begin developing applications on the Android platform using the Java programming language.
  • os161 file list

overall

搜索

  •  

最新評論

閱讀排行榜

評論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            欧美日韩三级| 欧美深夜福利| 你懂的亚洲视频| 另类亚洲自拍| 欧美激情影院| 欧美日韩美女在线| 国产精品高潮视频| 国产日韩欧美亚洲| 狠狠v欧美v日韩v亚洲ⅴ| 一区二区视频在线观看| 激情六月婷婷综合| 亚洲丰满在线| 99国产精品视频免费观看| 一区二区三区 在线观看视| 亚洲午夜av电影| 欧美在线短视频| 久久中文精品| 亚洲国内高清视频| 亚洲精品在线观| 亚洲一区中文| 久久精品99国产精品酒店日本| 久久综合电影| 欧美日韩国产成人在线91| 国产精品成人免费视频| 国产一区二区精品在线观看| 伊人成年综合电影网| 99在线精品视频在线观看| 亚洲欧美高清| 欧美1区免费| aⅴ色国产欧美| 久久国产毛片| 欧美人与性动交a欧美精品| 国产精品揄拍500视频| 激情一区二区| 亚洲一区二区欧美日韩| 久久久国产成人精品| 亚洲国产视频直播| 亚洲制服丝袜在线| 免费永久网站黄欧美| 欧美体内谢she精2性欧美| 狠狠88综合久久久久综合网| 9色精品在线| 久久婷婷丁香| 99视频在线精品国自产拍免费观看| 午夜亚洲一区| 欧美日韩国内| 国产一区二区激情| 一区二区日本视频| 免费观看日韩av| 亚洲一卡二卡三卡四卡五卡| 久久免费视频这里只有精品| 国产精品久久久一区二区| 亚洲国产天堂久久国产91| 亚洲欧美日韩国产精品| 亚洲国产精品电影在线观看| 午夜精品在线看| 欧美日韩国产在线播放| 亚洲大片精品永久免费| 亚洲欧美日韩第一区 | 91久久在线观看| 欧美一二三视频| 欧美日韩在线电影| 亚洲人成久久| 久久久久久久久久久成人| 亚洲免费av电影| 玖玖国产精品视频| 国产在线视频不卡二| 亚洲一区二区三区午夜| 亚洲国产精品美女| 久久久久国产精品午夜一区| 国产精品免费电影| 9l国产精品久久久久麻豆| 欧美国产欧美亚洲国产日韩mv天天看完整| 亚洲欧美成人一区二区在线电影| 欧美日韩第一区| 亚洲日本中文字幕| 免费成人性网站| 欧美在线看片a免费观看| 国产精品超碰97尤物18| 99精品视频网| 亚洲国产视频一区| 免费观看成人| 亚洲国产精品精华液网站| 久久亚洲一区二区| 欧美一区2区三区4区公司二百| 国产精品劲爆视频| 亚洲综合色视频| 日韩亚洲在线观看| 欧美日韩视频一区二区三区| 99国产精品自拍| 亚洲人成在线免费观看| 欧美激情第10页| 亚洲精品一线二线三线无人区| 欧美成人精品在线观看| 久久蜜桃资源一区二区老牛 | 国产午夜一区二区三区| 欧美亚洲免费| 亚洲欧美日韩国产中文| 国产嫩草影院久久久久| 欧美在线视频观看| 午夜视频久久久久久| 国产日产精品一区二区三区四区的观看方式 | 欧美一区二区日韩| 亚洲欧美日韩精品久久久| 国产乱码精品一区二区三区忘忧草| 亚洲综合日韩在线| 亚洲免费在线观看| 国产亚洲欧美激情| 久久一区中文字幕| 美女成人午夜| 日韩一级精品| 一本色道久久加勒比88综合| 国产精品黄页免费高清在线观看| 午夜亚洲精品| 欧美一区在线视频| 在线观看视频一区二区欧美日韩| 欧美成人午夜77777| 欧美搞黄网站| 亚洲午夜小视频| 亚洲欧美在线观看| 在线国产亚洲欧美| 91久久综合| 国产精品乱码一区二三区小蝌蚪| 午夜精品视频在线| 久久精彩视频| 亚洲精品一区二区三| 99国产一区| 国产亚洲欧美中文| 欧美国产日韩一二三区| 欧美日韩综合视频| 久久久av网站| 欧美成人中文字幕| 午夜精品久久久久久| 久久久久国产精品www| 99re视频这里只有精品| 亚洲一区图片| 亚洲国产精品一区二区尤物区| 亚洲乱码久久| 国语自产偷拍精品视频偷 | 久久久久久久久久看片| 免费一级欧美片在线播放| 亚洲一区精品在线| 久久久久久久综合日本| 一区二区不卡在线视频 午夜欧美不卡'| 亚洲视频免费在线| 伊人久久婷婷色综合98网| 日韩视频一区二区三区在线播放| 国产麻豆成人精品| 亚洲国产专区| 国产中文一区二区| 日韩午夜三级在线| 激情综合色丁香一区二区| 日韩亚洲欧美成人| 一区视频在线| 亚洲一区二区视频在线| 亚洲区欧美区| 欧美在线观看天堂一区二区三区 | 91久久久国产精品| 国内精品久久久久影院薰衣草| 亚洲精品中文字幕有码专区| 激情综合久久| 亚洲女同性videos| 一本久久a久久精品亚洲| 久久久九九九九| 午夜精品一区二区在线观看| 欧美高清视频在线观看| 久久久亚洲国产天美传媒修理工| 欧美视频一区| 亚洲高清影视| 影音先锋亚洲一区| 午夜精品福利在线观看| 在线中文字幕日韩| 欧美jjzz| 蜜桃av一区二区在线观看| 国产美女精品视频| 99在线热播精品免费99热| 最新日韩中文字幕| 久久精品五月| 久久精品视频va| 国产精品日日摸夜夜添夜夜av| 亚洲精品一区二区三区婷婷月 | 欧美在线看片| 欧美一区二区免费| 国产精品成人在线观看| 亚洲精品视频中文字幕| 亚洲人成免费| 麻豆久久精品| 欧美成人一区二免费视频软件| 国产一区二区三区久久 | 亚洲精品久久久久久久久久久久久| 久久九九99视频| 久久久久久穴| 国模大胆一区二区三区| 午夜影视日本亚洲欧洲精品| 欧美一级一区| 国产精品中文字幕欧美| 亚洲欧美日韩国产| 午夜一区二区三视频在线观看| 国产精品福利av| 亚洲一级片在线看|