• <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源碼剖析

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

            strlen的函數原形如下:

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

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

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

            1?size_t?strlen_a(const?char?* str)?{
            2?????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;
            3?????while?(*cp++
            )
            4?
            ????????;
            5?????return?(cp?-?str?-?1
            );
            6?}

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


            NOTE:
            數據對齊(data alignment),是指數據所在的內存地址必須是該數據長度的整數倍,這樣CPU的存取速度最快。比如在32位的計算機中,一個WORD為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;
            ?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語言實現雖然不算特別復雜,但也值得花點時間來弄清楚,先看9-14行:
            for?(char_ptr?=?str;?((ulong)char_ptr?&?(sizeof(ulong)?-?1))?!=?0;?++char_ptr)?{
            ????
            if?(*char_ptr?==?'\0'
            )
            ????????
            return?char_ptr?-
            ?str;
            }

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

            第16行將longword_ptr指向數據對齊后的首地址

            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的字節
            if?((((longword?+?magic_bits)?^?~longword)?&?~magic_bits)?!=?0)
            if語句中的計算可以分為如下3步:
            (1) longword + magic_bits
            其中magic_bits的二進制表示如下:
            ??????????????????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字節:
            如果longword 中有一個字節的所有bit都為0,則進行加法后,從這個字節的右邊的字節傳遞來的進位都會落到這個字節的最低位所在的hole上,而從這個字節的最高位則永遠不會產生向左邊字節的hole的進位。則這個字節左邊的hole在進行加法后不會改變,由此可以檢測出0字節;相反,如果longword中所有字節都不為0,則每個字節中至少有1位為1,進行加法后所有的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傳遞過來的進位只可能是0或1,很顯然b1永遠也不會產生進位,所以加法后longword的第16 bit這個hole不會變。

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

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

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

            一旦檢測出longword中有為0的字節,后面的代碼只需要找到第一個為0的字節并返回相應的長度就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. 另一種實現
            ?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的二進制表示如下:
            ????????????????b3??????b2???????b1???????b0
            ????????????
            31------------------------------->0

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

            在這種方法中假設所有字符都是ASCII標準字符,其值在0-127之間,因此longword總是如下形式:
            ????????????????b3??????b2???????b1???????b0
            ????????????
            31------------------------------->0

            ??longword:?
            0XXXXXXX 0XXXXXXX?0XXXXXXX?0XXXXXXX

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

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

            根據上面的描述,如果longword中有為0的字節,則if中的表達式結果為非0,否則為0。

            5. 匯編實現
            VC CRT的匯編實現與前面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. 測試結果
            為了對上述各種實現的效率有一個大概的認識,我在VC8和GCC下分別進行了測試,測試時均采用默認優化方式。下面是在GCC下運行幾百萬次后的結果(在VC8下的運行結果與此相似):
            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 2007-10-12 13:19 螞蟻終結者 閱讀(30991) 評論(34)  編輯 收藏 引用 所屬分類: The Annotated CRT Sources

            Feedback

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

            果然很快,效率高啊  回復  更多評論   

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

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

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

            這個什么意思?  回復  更多評論   

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

            可能我說的不夠清楚,看下面的例子:
                               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逐位比較,如果有某個位相同,就說這個位在加法后未改變,這樣在a中為1的位就是未改變的。
             
            result = a & ~magic_bits;
            得到未改變的hole位,從上例可以看出第16 bit這個hole加法后未改變,這樣就檢測出了0字節。
             
              回復  更多評論   

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

            贊啊!以前不懂的今天終于看懂了!  回復  更多評論   

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

            樓主剖析得全面,頂 !  回復  更多評論   

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

            只能檢測0~127,是個問題,最好能兼容0~255,有部分制表符和擴展字符位于這個區域。  回復  更多評論   

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

            實際上0~255都能檢測出來的:
            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;
            如果上面的語句執行完還沒有return,則會繼續下一次循環,這樣還是能檢測到在if語句中漏掉的128~255,只不過效率上會有所損失。如果要檢測0~255之間的字符,strlen_c比strlen_d要好。因為strlen_c只會漏掉這樣的WORD:
                10000000 XXXXXXXX XXXXXXXX XXXXXXXX
              回復  更多評論   

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

            為了便于下面的討論,這里假設所用的計算機為32位,即一個WORD為4個字節?呵呵,筆誤吧?
              回復  更多評論   

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

            Sorry,我不該用WORD這個單詞。我說的WORD在這里表示計算機中的一個字長,不是一般為2個字節的WORD類型。
              回復  更多評論   

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

            另外,是否有endian的問題呢?  回復  更多評論   

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

            想了想,應該沒有,呵呵  回復  更多評論   

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

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

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

            可以看出,上面VC的匯編實現是針對X86計算機的。
              回復  更多評論   

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

            如果能做到這樣的分析,還有什么能學不會?!  回復  更多評論   

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

            幾天前看過的文章怎么又跑前面來了?!  回復  更多評論   

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

            我也奇怪,就改了一下,再發布就變了。連日期都變了,郁悶。。。  回復  更多評論   

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

            不過是好文章,多看幾遍也不錯~  回復  更多評論   

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

            強!希望這樣的好文不要鏈接失效!o(∩_∩)o...  回復  更多評論   

            # 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 這個轉換把一個 char * 轉成 ulong 會發生什么事情?  回復  更多評論   

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

            想了想這個問題問得挺幼稚,我理解 (ulong)char_ptr應該得到一個ulong的值,這個值就是指針char_ptr的值。  回復  更多評論   

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

            you gotta it!  回復  更多評論   

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

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

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

            @福福
            中文字符應該用wcslen才對,strlen是用來處理單字節字符串的。
            詳細描述請看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.
              回復  更多評論   

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

            幾年沒動過匯編了,看了代碼,有種耳目一新的感覺~~~~~~~~  回復  更多評論   

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

            感謝博主的精彩剖析。
            感覺到我不會的東西太多了
            由此堅定了我看GNU C的決心
            謝謝  回復  更多評論   

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

            博主的文章允許轉載么?
            昨天看glibc里的注釋覺得云里霧里
            今天看了博主的文章,突然覺得豁然開朗啊 ;-)
            還有想問一個問題 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位呢?  回復  更多評論   

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

            @star
            歡迎轉載,轉載當然是沒有問題的,畢竟寫文章就是能讓更多的人看到!

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

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

            似乎CRT庫的這種寫法有點越界訪問的意思,呵呵。  回復  更多評論   

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

            @福福
            strlen算法在處理中文時不會出問題,關鍵點在后面的if(cp[?]==0)。
            不過處理中文時效率會跟最簡單的strlen一樣。  回復  更多評論   

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

            分析得很清楚,寫得也很詳細,贊一個。  回復  更多評論   

            # 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;
            }

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

            求各位指出上述論證錯誤在哪。另外,我沒明白此例中內存對齊到滿足哪種條件才能提高代碼效率。  回復  更多評論   

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

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

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

            學習,謝謝分享  回復  更多評論   

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

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

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

            學習,學習,時刻關注。  回復  更多評論   

            天天久久狠狠色综合| 午夜精品久久久久久中宇| 人妻无码αv中文字幕久久| 久久只这里是精品66| 久久精品国产清自在天天线| 99久久综合国产精品二区| 久久精品国产91久久综合麻豆自制| 丰满少妇高潮惨叫久久久| 丰满少妇人妻久久久久久 | 久久国产精品-国产精品| 久久香蕉超碰97国产精品| 精品久久无码中文字幕| 久久久青草久久久青草| AA级片免费看视频久久| 国产AⅤ精品一区二区三区久久| 久久久久国产亚洲AV麻豆| 中文成人久久久久影院免费观看 | 久久久久久国产精品无码超碰| 国内精品伊人久久久久777| 无码久久精品国产亚洲Av影片| 99久久精品费精品国产一区二区| 久久亚洲国产中v天仙www| 久久精品国产精品亚洲| 亚洲精品乱码久久久久久蜜桃图片 | 亚洲?V乱码久久精品蜜桃| 一本色道久久88精品综合| 国产精品欧美久久久天天影视| 精品无码久久久久久久动漫| 人人妻久久人人澡人人爽人人精品 | 18禁黄久久久AAA片| 久久综合精品国产二区无码| 91久久精品无码一区二区毛片| 久久久91人妻无码精品蜜桃HD| 亚洲伊人久久精品影院| 国产亚洲美女精品久久久| 久久精品卫校国产小美女| 蜜桃麻豆www久久| 日韩精品久久久久久久电影蜜臀| 国产午夜福利精品久久| 久久青青草原精品国产| 波多野结衣久久精品|