• <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>

            #ant

            The dreams in which I'm dying are the best I've ever had...

            strlen源碼剖析

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

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

            ??????size_t strlen(const char *str);

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

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


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

            為了便于下面的討論,這里假設(shè)所用的計(jì)算機(jī)為32位,即一個(gè)WORD為4個(gè)字節(jié)。下面給出在32位計(jì)算機(jī)上的C語言實(shí)現(xiàn)(假設(shè)unsigned long為4個(gè)字節(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語言實(shí)現(xiàn)雖然不算特別復(fù)雜,但也值得花點(diǎn)時(shí)間來弄清楚,先看9-14行:
            for?(char_ptr?=?str;?((ulong)char_ptr?&?(sizeof(ulong)?-?1))?!=?0;?++char_ptr)?{
            ????
            if?(*char_ptr?==?'\0'
            )
            ????????
            return?char_ptr?-
            ?str;
            }

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

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

            longword_ptr?=?(ulong*)char_ptr;

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

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

            第24行的if語句是整個(gè)算法的核心,該語句判斷22行讀入的WORD中是否有為0的字節(jié)
            if?((((longword?+?magic_bits)?^?~longword)?&?~magic_bits)?!=?0)
            if語句中的計(jì)算可以分為如下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,我們把這幾個(gè)bits稱為holes,注意在每個(gè)byte的左邊都有一個(gè)hole。

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

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

            (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這個(gè)hole不會(huì)變,這說明我們無法檢測(cè)出b3為10000000的所有WORD。值得慶幸的是用于strlen的字符串都是ASCII標(biāo)準(zhǔn)字符,其值在0-127之間,這意味著每一個(gè)字節(jié)的第一個(gè)bit都為0。因此上面的算法是安全的。

            一旦檢測(cè)出longword中有為0的字節(jié),后面的代碼只需要找到第一個(gè)為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. 另一種實(shí)現(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語句中的計(jì)算可以分為如下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

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

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

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

            5. 匯編實(shí)現(xiàn)
            VC CRT的匯編實(shí)現(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????(?0,?1,?0,?0,?0,?0?)
            ?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. 測(cè)試結(jié)果
            為了對(duì)上述各種實(shí)現(xiàn)的效率有一個(gè)大概的認(rèn)識(shí),我在VC8和GCC下分別進(jìn)行了測(cè)試,測(cè)試時(shí)均采用默認(rèn)優(yōu)化方式。下面是在GCC下運(yùn)行幾百萬次后的結(jié)果(在VC8下的運(yùn)行結(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
            --------------------------------------------------

            源代碼:點(diǎn)擊下載

            posted on 2007-10-12 13:19 螞蟻終結(jié)者 閱讀(30993) 評(píng)論(34)  編輯 收藏 引用 所屬分類: The Annotated CRT Sources

            Feedback

            # re: strlen源碼剖析 2007-09-26 19:29 msdn47

            果然很快,效率高啊  回復(fù)  更多評(píng)論   

            # re: strlen源碼剖析 2007-09-26 21:29 hi

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

            ======================================

            這個(gè)什么意思?  回復(fù)  更多評(píng)論   

            # re: strlen源碼剖析 2007-09-27 08:19 螞蟻終結(jié)者

            可能我說的不夠清楚,看下面的例子:
                               b3      b2       b1       b0
                           31------------------------------->0
                 longword: 00001001 00011000 00000000 00001100
            +  magic_bits: 01111110 11111110 11111110 11111111
                      sum: 10001000 00010110 11111111 00001011
            ^   ~longword: 11110110 11100111 11111111 11110011
                        a: 01111110 11110001 00000000 11111000
            & ~magic_bits: 10000001 00000001 00000001 00000000
                   result: 00000000 00000001 00000000 00000000
            sum = longword + magic_bits;
            a = sum ^ ~longword;
            即用sum與longword逐位比較,如果有某個(gè)位相同,就說這個(gè)位在加法后未改變,這樣在a中為1的位就是未改變的。
             
            result = a & ~magic_bits;
            得到未改變的hole位,從上例可以看出第16 bit這個(gè)hole加法后未改變,這樣就檢測(cè)出了0字節(jié)。
             
              回復(fù)  更多評(píng)論   

            # re: strlen源碼剖析 2007-09-27 08:28 wangmuy

            贊啊!以前不懂的今天終于看懂了!  回復(fù)  更多評(píng)論   

            # re: strlen源碼剖析[未登錄] 2007-09-27 08:42 漂舟

            樓主剖析得全面,頂 !  回復(fù)  更多評(píng)論   

            # re: strlen源碼剖析 2007-09-27 08:52 Yong Sun

            只能檢測(cè)0~127,是個(gè)問題,最好能兼容0~255,有部分制表符和擴(kuò)展字符位于這個(gè)區(qū)域。  回復(fù)  更多評(píng)論   

            # re: strlen源碼剖析 2007-09-27 09:06 螞蟻終結(jié)者

            實(shí)際上0~255都能檢測(cè)出來的:
            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;
            如果上面的語句執(zhí)行完還沒有return,則會(huì)繼續(xù)下一次循環(huán),這樣還是能檢測(cè)到在if語句中漏掉的128~255,只不過效率上會(huì)有所損失。如果要檢測(cè)0~255之間的字符,strlen_c比strlen_d要好。因?yàn)閟trlen_c只會(huì)漏掉這樣的WORD:
                10000000 XXXXXXXX XXXXXXXX XXXXXXXX
              回復(fù)  更多評(píng)論   

            # re: strlen源碼剖析 2007-09-27 09:23 k120

            為了便于下面的討論,這里假設(shè)所用的計(jì)算機(jī)為32位,即一個(gè)WORD為4個(gè)字節(jié)?呵呵,筆誤吧?
              回復(fù)  更多評(píng)論   

            # re: strlen源碼剖析 2007-09-27 09:35 螞蟻終結(jié)者

            Sorry,我不該用WORD這個(gè)單詞。我說的WORD在這里表示計(jì)算機(jī)中的一個(gè)字長,不是一般為2個(gè)字節(jié)的WORD類型。
              回復(fù)  更多評(píng)論   

            # re: strlen源碼剖析 2007-09-27 10:32 Yong Sun

            另外,是否有endian的問題呢?  回復(fù)  更多評(píng)論   

            # re: strlen源碼剖析 2007-09-27 10:39 Yong Sun

            想了想,應(yīng)該沒有,呵呵  回復(fù)  更多評(píng)論   

            # re: strlen源碼剖析 2007-09-27 11:16 螞蟻終結(jié)者

            c語言的版本不會(huì)有endian的問題,如果用匯編就需要注意了。
            假設(shè)有4個(gè)連續(xù)的字節(jié)abcd,現(xiàn)在要找出其中的第一個(gè)0字節(jié):
            1. 在PowerPC這種big-endian的計(jì)算機(jī)上,將這4個(gè)字節(jié)讀到寄存器中依然是
            abcd,從左到右找到最左邊的0字節(jié)就OK了。

            2. 在X86這種little-endian的計(jì)算機(jī)上,將這4個(gè)字節(jié)讀到寄存器中就會(huì)變成
            dcba,這就需要從右到左找到最右邊的0字節(jié)。

            可以看出,上面VC的匯編實(shí)現(xiàn)是針對(duì)X86計(jì)算機(jī)的。
              回復(fù)  更多評(píng)論   

            # re: strlen源碼剖析 2007-09-27 12:51 ∑x

            如果能做到這樣的分析,還有什么能學(xué)不會(huì)?!  回復(fù)  更多評(píng)論   

            # re: strlen源碼剖析 2007-10-12 16:36 Minidx全文檢索

            幾天前看過的文章怎么又跑前面來了?!  回復(fù)  更多評(píng)論   

            # re: strlen源碼剖析 2007-10-12 16:43 螞蟻終結(jié)者

            我也奇怪,就改了一下,再發(fā)布就變了。連日期都變了,郁悶。。。  回復(fù)  更多評(píng)論   

            # re: strlen源碼剖析 2007-10-12 17:04 Minidx全文檢索

            不過是好文章,多看幾遍也不錯(cuò)~  回復(fù)  更多評(píng)論   

            # re: strlen源碼剖析 2007-10-13 09:24 erran

            強(qiáng)!希望這樣的好文不要鏈接失效!o(∩_∩)o...  回復(fù)  更多評(píng)論   

            # re: strlen源碼剖析 2007-11-02 13:04 really green

            for (char_ptr = str; ((ulong)char_ptr
            & (sizeof(ulong) - 1)) != 0 ;
            ++ char_ptr) {
            if (*char_ptr == '\0' )
            return char_ptr - str;
            }

            我比較菜,這里就看不明白:
            ((ulong)char_ptr
            & (sizeof(ulong) - 1)) != 0 ;

            (ulong)char_ptr 這個(gè)轉(zhuǎn)換把一個(gè) char * 轉(zhuǎn)成 ulong 會(huì)發(fā)生什么事情?  回復(fù)  更多評(píng)論   

            # re: strlen源碼剖析 2007-11-02 19:28 really green

            想了想這個(gè)問題問得挺幼稚,我理解 (ulong)char_ptr應(yīng)該得到一個(gè)ulong的值,這個(gè)值就是指針char_ptr的值。  回復(fù)  更多評(píng)論   

            # re: strlen源碼剖析 2007-11-04 09:35 螞蟻終結(jié)者

            you gotta it!  回復(fù)  更多評(píng)論   

            # re: strlen源碼剖析 2007-12-04 05:39 福福

            如果有中文字符,這個(gè)是不是有問題
            if (((longword - lomagic) & himagic) != 0)  回復(fù)  更多評(píng)論   

            # re: strlen源碼剖析 2007-12-05 19:39 螞蟻終結(jié)者

            @福福
            中文字符應(yīng)該用wcslen才對(duì),strlen是用來處理單字節(jié)字符串的。
            詳細(xì)描述請(qǐng)看MSDN:
            However, strlen interprets the string as a single-byte character string, so its return value is always equal to the number of bytes, even if the string contains multibyte characters. wcslen is a wide-character version of strlen; the argument of wcslen is a wide-character string and the count of characters is in wide (two-byte) characters.
              回復(fù)  更多評(píng)論   

            # re: strlen源碼剖析 2007-12-27 14:01 Fox

            幾年沒動(dòng)過匯編了,看了代碼,有種耳目一新的感覺~~~~~~~~  回復(fù)  更多評(píng)論   

            # re: strlen源碼剖析 2007-12-31 17:44 Sunky

            感謝博主的精彩剖析。
            感覺到我不會(huì)的東西太多了
            由此堅(jiān)定了我看GNU C的決心
            謝謝  回復(fù)  更多評(píng)論   

            # re: strlen源碼剖析 2008-09-07 16:11 star

            博主的文章允許轉(zhuǎn)載么?
            昨天看glibc里的注釋覺得云里霧里
            今天看了博主的文章,突然覺得豁然開朗啊 ;-)
            還有想問一個(gè)問題 glibc里是這樣處理64位的
            if (sizeof (longword) > 4)
            {
            /* 64-bit version of the magic. */
            /* Do the shift in two steps to avoid a warning if long has 32 bits. */
            magic_bits = ((0x7efefefeL << 16) << 16) | 0xfefefeffL;
            himagic = ((himagic << 16) << 16) | himagic;
            lomagic = ((lomagic << 16) << 16) | lomagic;
            }
            為什么不一次就移32位呢?  回復(fù)  更多評(píng)論   

            # re: strlen源碼剖析 2008-09-07 19:54 螞蟻終結(jié)者

            @star
            歡迎轉(zhuǎn)載,轉(zhuǎn)載當(dāng)然是沒有問題的,畢竟寫文章就是能讓更多的人看到!

            為什么不一次就移32位呢?
            我也不太清楚,可能就其中注釋所說:
            /* Do the shift in two steps to avoid a warning if long has 32 bits. */
            只是為了避免warn吧呵呵!  回復(fù)  更多評(píng)論   

            # re: strlen源碼剖析 2008-11-07 11:42 test

            似乎CRT庫的這種寫法有點(diǎn)越界訪問的意思,呵呵。  回復(fù)  更多評(píng)論   

            # re: strlen源碼剖析 2009-03-18 17:08 123

            @福福
            strlen算法在處理中文時(shí)不會(huì)出問題,關(guān)鍵點(diǎn)在后面的if(cp[?]==0)。
            不過處理中文時(shí)效率會(huì)跟最簡單的strlen一樣。  回復(fù)  更多評(píng)論   

            # re: strlen源碼剖析 2009-04-29 14:32 uestc

            分析得很清楚,寫得也很詳細(xì),贊一個(gè)。  回復(fù)  更多評(píng)論   

            # re: strlen源碼剖析 2009-06-05 14:06 宋兵乙

            for (char_ptr = str; ((ulong)char_ptr
            & (sizeof(ulong) - 1)) != 0 ;
            ++ char_ptr) {
            if (*char_ptr == '\0' )
            return char_ptr - str;
            }

            如上的代碼我看不懂了,我的分析如下,麻煩各位高手指出錯(cuò)誤。
            sizeof(ulong)-1等于3,也就是二進(jìn)制的0000 0011,于是想要跳出for循環(huán),只需char_ptr的最后兩位是0即可。而每次for循環(huán)時(shí),char_ptr執(zhí)行了++操作,由于char_ptr是指向char的指針,因此每次++應(yīng)該是增加一個(gè)char的長度就是8。表現(xiàn)在二進(jìn)制上就是倒數(shù)第4位增加1,而后兩位是不會(huì)變化的。故得出結(jié)論若char_ptr的初始值不滿足最后兩位是0,那for就永遠(yuǎn)是死循環(huán)了。。

            求各位指出上述論證錯(cuò)誤在哪。另外,我沒明白此例中內(nèi)存對(duì)齊到滿足哪種條件才能提高代碼效率。  回復(fù)  更多評(píng)論   

            # re: strlen源碼剖析 2009-06-08 11:51 螞蟻終結(jié)者

            @宋兵乙
            “由于char_ptr是指向char的指針,因此每次++應(yīng)該是增加一個(gè)char的長度就是8”
            看來你對(duì)指針運(yùn)算還不太了解,建議好好復(fù)習(xí)一下指針部分。
            授人魚不如授人漁呵呵  回復(fù)  更多評(píng)論   

            # re: strlen源碼剖析 2009-10-29 11:31 似水之心

            學(xué)習(xí),謝謝分享  回復(fù)  更多評(píng)論   

            # re: strlen源碼剖析 2010-07-31 20:38 hoodlum1980

            不錯(cuò)。我今天反匯編看到strlen的匯編代碼一直覺得很奇怪,
            沒搞懂這幾句話在干什么。。。看了這篇文章很有幫助。
              回復(fù)  更多評(píng)論   

            # re: strlen源碼剖析 2010-11-07 14:37 郭龍

            學(xué)習(xí),學(xué)習(xí),時(shí)刻關(guān)注。  回復(fù)  更多評(píng)論   


            只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


            久久综合鬼色88久久精品综合自在自线噜噜| 久久无码高潮喷水| 午夜精品久久久久久久久| 久久亚洲综合色一区二区三区| 久久人人爽人人爽人人片AV高清| 91精品国产91久久久久久| 久久国产精品成人影院| yy6080久久| 午夜肉伦伦影院久久精品免费看国产一区二区三区 | 久久久久久久91精品免费观看| 2020最新久久久视精品爱| 国产亚洲精品自在久久| 精品国产乱码久久久久久人妻| 久久久久亚洲?V成人无码| 亚洲国产精品久久久久网站 | 亚洲国产二区三区久久| 99久久国产热无码精品免费| 久久午夜夜伦鲁鲁片免费无码影视 | 亚洲精品乱码久久久久久蜜桃图片| 精品久久久久国产免费| 99久久亚洲综合精品网站| 国产精品久久网| 久久精品国产亚洲AV嫖农村妇女| 精品熟女少妇AV免费久久| 久久免费看黄a级毛片| 中文成人无码精品久久久不卡| 久久久久久无码国产精品中文字幕| 国产精品内射久久久久欢欢| 99久久精品费精品国产| 99久久综合狠狠综合久久| 狠狠精品久久久无码中文字幕 | 色老头网站久久网| 色妞色综合久久夜夜| 久久久久99这里有精品10| 热RE99久久精品国产66热| 久久只这里是精品66| 中文字幕日本人妻久久久免费 | 无码专区久久综合久中文字幕 | 精品99久久aaa一级毛片| 国内精品伊人久久久久影院对白| 久久99精品久久久久久噜噜|