簡說GLIBC strncpy實現

版權聲明:轉載時請以超鏈接形式標明文章原始出處和作者信息及本聲明
http://bigwhite.blogbus.com/logs/37947818.html

比較以下兩組代碼,你認爲哪組運行的更快些呢?
Example1:
        int n   = 100;
        int n4  = n >> 2;
        int i   = 0;

        int a[100];

        for (i = 0; i < n4 ;i += 4) {
                a[i] = i;
                a[i+1] = i+1;
                a[i+2] = i+2;
                a[i+3] = i+3;
        }

Example2:
       for (i = 0;i < 100;i++) {
             a[i] = i;
       }

其實這個問題在"代碼大全2nd"中也有討論,從"代碼大全"中的統計結果來看,一般來說Example1更佔有優勢。我在solaris上做了測試,在未開優化的情況下:兩者運行時間分別爲2ms和6ms;在打開-O2優化後,兩者均爲1ms。這種通過減少循環次數的方法在GLIBC中也有體現,比如說strncpy的實現:

下面是strncpy的GLIBC源碼:
char *
x_strncpy (s1, s2, n)
        char *s1;
        const char *s2;
        size_t n;
{
        reg_char c;
        char *s = s1;

        --s1;

        if (n >= 4)
        {
                size_t n4 = n >> 2; /* n4 = n / 4, n4表示下面的循環執行的次數*/

                for (;;)
                {
                        c = *s2++;
                        *++s1 = c;
                        if (c == '/0')
                                break;
                        c = *s2++;
                        *++s1 = c;
                        if (c == '/0')
                                break;
                        c = *s2++;
                        *++s1 = c;
                        if (c == '/0')
                                break;
                        c = *s2++;
                        *++s1 = c;
                        if (c == '/0')
                                break;
                        if (--n4 == 0)
                                goto last_chars;  /* 如果n = 10,s2 = "hello world",則兩輪循環後,還有"尾巴"沒有copy完,在last_chars處繼續處理 */
                }
                n = n - (s1 - s) - 1;  /* 還沒有copy完n個字節,s2就到達末尾了,跳到zero_fill處繼續爲s1補零 */
                if (n == 0)
       return s;
                goto zero_fill;
        }

last_chars:     
        n &= 3;       /* n = n & 3 結果 n <= 3,n即爲上面循環過後"尾巴字符"的數量 */
        if (n == 0)
                return s;
        do
        {
                c = *s2++;
                *++s1 = c;
                if (--n == 0)
                        return s;
        } while (c != '/0');

zero_fill:       
        do
                *++s1 = '/0';
        while (--n > 0);

        return s;
}

相比於strlen的實現,strncpy的實現更易理解。其字面上的邏輯就是每四個字節(n>>2)作爲一組,每組逐個字節進行拷貝賦值,其內在目的則是減少循環次數,以獲得性能的提升。要想知道爲什麼減少循環次數能提升性能的話,那就要深入到彙編層面去了,這裏不再詳述。另外還要一提的是GLIBC中的strncmp,strncat的實現也遵循着與上面同樣的邏輯。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章