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)