8、特定區域的字符串比較和轉換strcoll,strxfrm,wcscoll,wcsxfrm:strcoll使用當前的區域設置來比較字符串,strxfrm使用當前的區域設置來轉換字符串。當前區域設置由LL_COLLATE宏指定。它們均調用帶有區域設置參數的內部版本strcoll_l和strxfrm_l來完成實際的工作。
-
- #include <string.h>
- #ifndef STRING_TYPE
- # define STRING_TYPE char
- # define STRCOLL strcoll
- # define STRCOLL_L __strcoll_l
- # define USE_HIDDEN_DEF
- #endif
- #include "../locale/localeinfo.h"
- int
- STRCOLL (s1, s2)
- const STRING_TYPE *s1;
- const STRING_TYPE *s2;
- {
- return STRCOLL_L (s1, s2, _NL_CURRENT_LOCALE);
- }
- #ifdef USE_HIDDEN_DEF
- libc_hidden_def (STRCOLL)
- #endif
-
- #include <string.h>
- #include <locale/localeinfo.h>
- #ifndef STRING_TYPE
- # define STRING_TYPE char
- # define STRXFRM strxfrm
- # define STRXFRM_L __strxfrm_l
- #endif
- size_t
- STRXFRM (STRING_TYPE *dest, const STRING_TYPE *src, size_t n)
- {
- return STRXFRM_L (dest, src, n, _NL_CURRENT_LOCALE);
- }
9、錯誤消息報告strerror:獲取錯誤碼errnum的字符串描述,在下一次調用strerror之前這個字符串存儲空間不能修改,對這個空間進行寫操作會導致未定義的行為。若獲取沒有成功,則使用errno全局變量(或全局宏)中的錯誤碼來獲取錯誤消息。
-
- #include <libintl.h> /* 有很多內部接口 */
- #include <stdio.h>
- #include <string.h>
- #include <errno.h> /* errno中保存了程序的錯誤碼 */
-
-
- libc_freeres_ptr (static char *buf);
- char *
- strerror (errnum)
- int errnum;
- {
- char *ret = __strerror_r (errnum, NULL, 0);
- int saved_errno;
- if (__builtin_expect (ret != NULL, 1))
- return ret;
-
- saved_errno = errno;
- if (buf == NULL)
- buf = malloc (1024);
- __set_errno (saved_errno);
- if (buf == NULL)
- return _("Unknown error");
- return __strerror_r (errnum, buf, 1024);
- }
10、內存塊復制memcpy,memmove,wmemcpy,wmemmove:memcpy從SRC中復制N個字節的內容到DEST中,memmove從SRC中復制N個字節的內容到DEST中,保證對重疊字符串(即SRC與DEST共用存儲空間)有正確的行為。這兩個函數的實現使用了memcopy.h和pagecopy.h中定義的內部接口,有按字節方式復制BYTE_COPY_FWD,按字方式復制WORD_COPY_FWD(一個字為unsigned long型)、按頁方式復制PAGE_COPY_FWD_MAYBE,這些接口都是以宏的形式提供的。
-
-
-
-
-
-
-
-
- #include <sys/cdefs.h>
- #include <endian.h>
-
-
-
-
-
-
-
-
- #define op_t unsigned long int
- #define OPSIZ (sizeof(op_t))
-
- typedef unsigned char byte;
-
- #define reg_char char
-
- #if __BYTE_ORDER == __LITTLE_ENDIAN /* 小端字節序:w0在低端,w1在高端 */
- #define MERGE(w0, sh_1, w1, sh_2) (((w0) >> (sh_1)) | ((w1) << (sh_2)))
- #endif
- #if __BYTE_ORDER == __BIG_ENDIAN /* 大端字節序:w0在高端,w1在低端 */
- #define MERGE(w0, sh_1, w1, sh_2) (((w0) << (sh_1)) | ((w1) >> (sh_2)))
- #endif
-
- #define BYTE_COPY_FWD(dst_bp, src_bp, nbytes) /
- do /
- { /
- size_t __nbytes = (nbytes); /
- while (__nbytes > 0) /
- { /
- byte __x = ((byte *) src_bp)[0]; /
- src_bp += 1; /
- __nbytes -= 1; /
- ((byte *) dst_bp)[0] = __x; /
- dst_bp += 1; /
- } /
- } while (0)
-
-
- #define BYTE_COPY_BWD(dst_ep, src_ep, nbytes) /
- do /
- { /
- size_t __nbytes = (nbytes); /
- while (__nbytes > 0) /
- { /
- byte __x; /
- src_ep -= 1; /
- __x = ((byte *) src_ep)[0]; /
- dst_ep -= 1; /
- __nbytes -= 1; /
- ((byte *) dst_ep)[0] = __x; /
- } /
- } while (0)
-
-
- extern void _wordcopy_fwd_aligned (long int, long int, size_t) __THROW;
- extern void _wordcopy_fwd_dest_aligned (long int, long int, size_t) __THROW;
- #define WORD_COPY_FWD(dst_bp, src_bp, nbytes_left, nbytes) /
- do /
- { /
- if (src_bp % OPSIZ == 0) /
- _wordcopy_fwd_aligned (dst_bp, src_bp, (nbytes) / OPSIZ); /
- else /
- _wordcopy_fwd_dest_aligned (dst_bp, src_bp, (nbytes) / OPSIZ); /
- src_bp += (nbytes) & -OPSIZ; /
- dst_bp += (nbytes) & -OPSIZ; /
- (nbytes_left) = (nbytes) % OPSIZ; /
- } while (0)
-
-
-
-
- extern void _wordcopy_bwd_aligned (long int, long int, size_t) __THROW;
- extern void _wordcopy_bwd_dest_aligned (long int, long int, size_t) __THROW;
- #define WORD_COPY_BWD(dst_ep, src_ep, nbytes_left, nbytes) /
- do /
- { /
- if (src_ep % OPSIZ == 0) /
- _wordcopy_bwd_aligned (dst_ep, src_ep, (nbytes) / OPSIZ); /
- else /
- _wordcopy_bwd_dest_aligned (dst_ep, src_ep, (nbytes) / OPSIZ); /
- src_ep -= (nbytes) & -OPSIZ; /
- dst_ep -= (nbytes) & -OPSIZ; /
- (nbytes_left) = (nbytes) % OPSIZ; /
- } while (0)
-
- #define OP_T_THRES 16
-
-
-
-
-
-
-
-
-
-
-
-
-
- #if PAGE_COPY_THRESHOLD
- #include <assert.h>
- #define PAGE_COPY_FWD_MAYBE(dstp, srcp, nbytes_left, nbytes) /
- do /
- { /
- if ((nbytes) >= PAGE_COPY_THRESHOLD && /
- PAGE_OFFSET ((dstp) - (srcp)) == 0) /
- { /
-
- /
- size_t nbytes_before = PAGE_OFFSET (-(dstp)); /
- if (nbytes_before != 0) /
- { /
- /
- WORD_COPY_FWD (dstp, srcp, nbytes_left, nbytes_before); /
- assert (nbytes_left == 0); /
- nbytes -= nbytes_before; /
- } /
- PAGE_COPY_FWD (dstp, srcp, nbytes_left, nbytes); /
- } /
- } while (0)
-
- #define PAGE_OFFSET(n) ((n) & (PAGE_SIZE - 1))
- #else
- #define PAGE_COPY_FWD_MAYBE(dstp, srcp, nbytes_left, nbytes)
- #endif
-
- #include <string.h>
- #include <memcopy.h> /* 包含了字節復制函數BYTE_COPY_FWD和字復制函數WORD_COPY_FWD */
- #include <pagecopy.h> /* 包含內存頁復制函數PAGE_COPY_FWD_MAYBE */
- #undef memcpy
-
- void *
- memcpy (dstpp, srcpp, len)
- void *dstpp;
- const void *srcpp;
- size_t len;
- {
- unsigned long int dstp = (long int) dstpp;
- unsigned long int srcp = (long int) srcpp;
-
-
- if (len >= OP_T_THRES)
- {
-
- len -= (-dstp) % OPSIZ;
- BYTE_COPY_FWD (dstp, srcp, (-dstp) % OPSIZ);
-
- PAGE_COPY_FWD_MAYBE (dstp, srcp, len, len);
-
-
- WORD_COPY_FWD (dstp, srcp, len, len);
-
- }
-
- BYTE_COPY_FWD (dstp, srcp, len);
- return dstpp;
- }
- libc_hidden_builtin_def (memcpy)
-
- #include <string.h>
- #include <memcopy.h> /* 包含了字節復制函數BYTE_COPY_FWD和字復制函數WORD_COPY_FWD */
- #include <pagecopy.h> /* 包含內存頁復制函數PAGE_COPY_FWD_MAYBE */
-
- #ifndef a1
- #define a1 dest /* 第一個實參是dest */
- #define a1const
- #define a2 src /* 第二個實參是src */
- #define a2const const
- #undef memmove
- #endif
- #if !defined(RETURN) || !defined(rettype)
- #define RETURN(s) return (s) /* 返回dest */
- #define rettype void *
- #endif
-
- rettype
- memmove (a1, a2, len)
- a1const void *a1;
- a2const void *a2;
- size_t len;
- {
- unsigned long int dstp = (long int) dest;
- unsigned long int srcp = (long int) src;
-
- if (dstp - srcp >= len)
- {
-
-
- if (len >= OP_T_THRES)
- {
-
- len -= (-dstp) % OPSIZ;
- BYTE_COPY_FWD (dstp, srcp, (-dstp) % OPSIZ);
-
- PAGE_COPY_FWD_MAYBE (dstp, srcp, len, len);
-
-
- WORD_COPY_FWD (dstp, srcp, len, len);
-
- }
-
- BYTE_COPY_FWD (dstp, srcp, len);
- }
- else
- {
-
- srcp += len;
- dstp += len;
-
- if (len >= OP_T_THRES)
- {
-
- len -= dstp % OPSIZ;
- BYTE_COPY_BWD (dstp, srcp, dstp % OPSIZ);
-
-
- WORD_COPY_BWD (dstp, srcp, len, len);
-
- }
-
- BYTE_COPY_BWD (dstp, srcp, len);
- }
- RETURN (dest);
- }
- #ifndef memmove
- libc_hidden_builtin_def (memmove)
- #endif
解釋:
(1)memcopy.h中,宏op_t為字的類型,定義為unsigned long,OPSIZ為字的大小(32位平臺中為4字節)。byte為字節的類型,定義為unsigned char。MERGE函數用于合并兩個字,根據不同的機器字節序,一個字在高端,一個字在低端。字節復制和字復制都有兩種方式,一種是向前復制,一種是向后復制。字復制時需要指針對齊到字的邊界(即指針變量中的值為OPSIZ的倍數),復制操作使用了編譯器內置的_wordcopy_fwd_aligned等函數。字節復制的接口中的代碼是很直接的,用一個while循環一個字節一個字節地進行拷貝即可。宏OP_T_THRES定義了能進行字復制的最低門檻值。
(2)pagecopy.h中,要復制的字節數必須達到一定的門檻值PAGE_COPY_THRESHOLD(這個值在內核中定義),才會執行按頁復制。PAGE_SIZE為頁的大小,在內核中定義,PAGE_OFFSET(n)用于計算頁的偏移。復制時先用WORD_COPY_FWD復制前面幾個字節,這樣就能讓源地址和目標地址按頁對齊,然后就可執行頁復制。
(3)有了這些宏,memcpy和memmove函數的實現就比較簡單了,直接用這些接口來進行復制操作,只不過要注意進行字復制或頁復制時要復制開頭的幾個字節,以對齊到字或頁的邊界。最后尾部可能還剩下幾個字節,用字節復制復制它們即可。
11、內存塊中的字符搜索memchr,wmemchr:在內存塊S的前N個字節中搜索C的第一次出現。算法實現與strlen及strchr類似。
12、內存塊比較memcmp,wmemcmp:對兩個內存塊的前N個字節進行比較。比較也是使用字(unsigned long型)的比較方式,以加快搜索速度。采用的策略是先比較開頭的幾個字節,以使塊指針對齊到字的邊界,再用memcmp_common_alignment(兩個內存塊都對齊的情況)或memcmp_not_common_alignment(一個內存塊對齊,而另一個沒有對齊)按字進行快速的比較,最后對剩下的幾個字節進行比較。代碼就不再解剖了,涉及到大量的字操作,以及用MERGE進行字合并(這需要考慮到機器的字節序)。
13、內存塊設置memset,wmemset:將內存塊的前LEN個字節設置為字符C。也是采用字的方式來進行快速地寫入。先設置了一個字cccc,其每個字節都是字符C。為了加快寫入速度,每循環一次就寫入8個cccc,最后對剩下的幾個字節寫入C。
-
- #include <string.h>
- #include <memcopy.h>
- #undef memset
-
- void *
- memset (dstpp, c, len)
- void *dstpp;
- int c;
- size_t len;
- {
- long int dstp = (long int) dstpp;
- if (len >= 8)
- {
- size_t xlen;
- op_t cccc;
-
-
- cccc = (unsigned char) c;
- cccc |= cccc << 8;
- cccc |= cccc << 16;
- if (OPSIZ > 4)
-
- cccc |= (cccc << 16) << 16;
-
-
- while (dstp % OPSIZ != 0)
- {
- ((byte *) dstp)[0] = c;
- dstp += 1;
- len -= 1;
- }
-
- xlen = len / (OPSIZ * 8);
- while (xlen > 0)
- {
- ((op_t *) dstp)[0] = cccc;
- ((op_t *) dstp)[1] = cccc;
- ((op_t *) dstp)[2] = cccc;
- ((op_t *) dstp)[3] = cccc;
- ((op_t *) dstp)[4] = cccc;
- ((op_t *) dstp)[5] = cccc;
- ((op_t *) dstp)[6] = cccc;
- ((op_t *) dstp)[7] = cccc;
- dstp += 8 * OPSIZ;
- xlen -= 1;
- }
- len %= OPSIZ * 8;
-
- xlen = len / OPSIZ;
- while (xlen > 0)
- {
- ((op_t *) dstp)[0] = cccc;
- dstp += OPSIZ;
- xlen -= 1;
- }
- len %= OPSIZ;
- }
-
- while (len > 0)
- {
- ((byte *) dstp)[0] = c;
- dstp += 1;
- len -= 1;
- }
- return dstpp;
- }
- libc_hidden_builtin_def (memset)