首页 > 编程 > .NET > 正文

C标准库源码解剖(6):字符串处理函数string.h和wchar.h(续)

2024-07-10 13:27:16
字体:
来源:转载
供稿:网友

8、特定区域的字符串比较和转换strcoll,strxfrm,wcscoll,wcsxfrm:strcoll使用当前的区域设置来比较字符串,strxfrm使用当前的区域设置来转换字符串。当前区域设置由LL_COLLATE宏指定。它们均调用带有区域设置参数的内部版本strcoll_l和strxfrm_l来完成实际的工作。

 

[cpp] view plaincopy
  1. /* strcoll.c:strcoll函数的实现 */  
  2. #include <string.h>  
  3. #ifndef STRING_TYPE  
  4. # define STRING_TYPE char  
  5. # define STRCOLL strcoll  
  6. # define STRCOLL_L __strcoll_l  
  7. # define USE_HIDDEN_DEF  
  8. #endif  
  9. #include "../locale/localeinfo.h"  
  10. int  
  11. STRCOLL (s1, s2)  
  12.      const STRING_TYPE *s1;  
  13.      const STRING_TYPE *s2;  
  14. {  
  15.   return STRCOLL_L (s1, s2, _NL_CURRENT_LOCALE);  
  16. }  
  17. #ifdef USE_HIDDEN_DEF  
  18. libc_hidden_def (STRCOLL)  
  19. #endif  

 

 

[cpp] view plaincopy
  1. /* strxfrm.c:strxfrm函数的实现  */  
  2. #include <string.h>  
  3. #include <locale/localeinfo.h>  
  4. #ifndef STRING_TYPE  
  5. # define STRING_TYPE char  
  6. # define STRXFRM strxfrm  
  7. # define STRXFRM_L __strxfrm_l  
  8. #endif  
  9. size_t  
  10. STRXFRM (STRING_TYPE *dest, const STRING_TYPE *src, size_t n)  
  11. {  
  12.   return STRXFRM_L (dest, src, n, _NL_CURRENT_LOCALE);  
  13. }  

 

    9、错误消息报告strerror:获取错误码errnum的字符串描述,在下一次调用strerror之前这个字符串存储空间不能修改,对这个空间进行写操作会导致未定义的行为。若获取没有成功,则使用errno全局变量(或全局宏)中的错误码来获取错误消息。

 

[cpp] view plaincopy
  1. /* strerror.c:strerror函数的实现  */  
  2. #include <libintl.h> /* 有很多内部接口 */  
  3. #include <stdio.h>  
  4. #include <string.h>  
  5. #include <errno.h>   /* errno中保存了程序的错误码 */  
  6. /* 返回错误码errnum的字符串描述,在下一次调用strerror之前这个字符串存储 
  7.     空间不能修改,对这个空间进行写操作会导致未定义的行为 */  
  8. libc_freeres_ptr (static char *buf); /* 存放字符串描述的全局空间 */  
  9. char *  
  10. strerror (errnum)  
  11.      int errnum;  
  12. {  
  13.   char *ret = __strerror_r (errnum, NULL, 0); /* 根据错误码获取错误消息 */  
  14.   int saved_errno;  
  15.   if (__builtin_expect (ret != NULL, 1)) /* 若错误消息获取成功,则返回它 */  
  16.     return ret;  
  17.   /* 否则获取errno中保存的程序错误码,用缓冲区buf来存储它的字符串描述 */  
  18.   saved_errno = errno;  
  19.   if (buf == NULL)  
  20.     buf = malloc (1024);  /* buf是一个全局缓冲区 */  
  21.   __set_errno (saved_errno); /* 设置错误码 */  
  22.   if (buf == NULL)  
  23.     return _("Unknown error");  
  24.   return __strerror_r (errnum, buf, 1024); /* 获取错误码对应的错误消息并返回 */  
  25. }  

 

    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,这些接口都是以宏的形式提供的。

 

[cpp] view plaincopy
  1. /* memcopy.h -- 在内存复制函数中使用的一些定义  */  
  2. /* 内存函数的复制策略是: 
  3.      1、复制字节,直到目标指针被对齐。 
  4.      2、在展开的循环中复制字。如果源指针和目标指针不是用 
  5.       同一种方式对齐,则使用字内存操作,但在写之前要对两个读取的字进行移位和合并 
  6.      3、复制剩下的几个字节 
  7.      在至少有10个寄存器用来给GCC使用的处理器上,这是非常快速的,并且能在一条指令中使用 
  8.     reg+const来访问内存  */  
  9. #include <sys/cdefs.h>  
  10. #include <endian.h>  
  11. /* 在本文件中定义的宏有: 
  12.    BYTE_COPY_FWD(dst_beg_ptr, src_beg_ptr, nbytes_to_copy) 
  13.    BYTE_COPY_BWD(dst_end_ptr, src_end_ptr, nbytes_to_copy) 
  14.    WORD_COPY_FWD(dst_beg_ptr, src_beg_ptr, nbytes_remaining, nbytes_to_copy) 
  15.    WORD_COPY_BWD(dst_end_ptr, src_end_ptr, nbytes_remaining, nbytes_to_copy) 
  16.    MERGE(old_word, sh_1, new_word, sh_2) 
  17. */  
  18. /* 用于对齐的内存操作类型,正常时它应该是能一次装载和存储的最大类型 */  
  19. #define op_t    unsigned long int  
  20. #define OPSIZ   (sizeof(op_t))  
  21. /* 用于未对齐的操作类型 */  
  22. typedef unsigned char byte;  
  23. /* 用于在寄存器中存储字节的优化类型 */  
  24. #define reg_char    char  
  25. /* 对两个字的合并操作 */  
  26. #if __BYTE_ORDER == __LITTLE_ENDIAN  /* 小端字节序:w0在低端,w1在高端 */  
  27. #define MERGE(w0, sh_1, w1, sh_2) (((w0) >> (sh_1)) | ((w1) << (sh_2)))  
  28. #endif  
  29. #if __BYTE_ORDER == __BIG_ENDIAN  /* 大端字节序:w0在高端,w1在低端 */  
  30. #define MERGE(w0, sh_1, w1, sh_2) (((w0) << (sh_1)) | ((w1) >> (sh_2)))  
  31. #endif  
  32. /* 向前复制:从SRC_BP中精确地复制NBTYES个字节到DST_BP中,无需对指针的对齐作任何假设  */  
  33. #define BYTE_COPY_FWD(dst_bp, src_bp, nbytes)                     /  
  34.   do                                          /  
  35.     {                                         /  
  36.       size_t __nbytes = (nbytes);                         /  
  37.       while (__nbytes > 0)                             /  
  38.     {                                     /  
  39.       byte __x = ((byte *) src_bp)[0];                    /  
  40.       src_bp += 1;                                /  
  41.       __nbytes -= 1;                              /  
  42.       ((byte *) dst_bp)[0] = __x;                         /  
  43.       dst_bp += 1;                                /  
  44.     }                                     /  
  45.     } while (0)  
  46. /* 向后复制:从SRC_END_PTR中精确地复制NBTYTES_TO_COPY个字节到DST_END_PTR中, 
  47.     复制从指针前面的字节右端开始,并且向着更小的地址方向前进。无需对指针的对齐作任何假设 */  
  48. #define BYTE_COPY_BWD(dst_ep, src_ep, nbytes)                     /  
  49.   do                                          /  
  50.     {                                         /  
  51.       size_t __nbytes = (nbytes);                         /  
  52.       while (__nbytes > 0)                             /  
  53.     {                                     /  
  54.       byte __x;                               /  
  55.       src_ep -= 1;                                /  
  56.       __x = ((byte *) src_ep)[0];                         /  
  57.       dst_ep -= 1;                                /  
  58.       __nbytes -= 1;                              /  
  59.       ((byte *) dst_ep)[0] = __x;                         /  
  60.     }                                     /  
  61.     } while (0)  
  62. /* 向前复制:从SRC_BP中复制最多NBYTES个字节到DST_BP中,假设DST_BP对齐到OPSIZ的倍数。 
  63.     如果不是所有的字节都能顺利的复制,剩下的字节数保存到NBYTES_LEFT中,否则存入0 */  
  64. extern void _wordcopy_fwd_aligned (long intlong intsize_t) __THROW;  
  65. extern void _wordcopy_fwd_dest_aligned (long intlong intsize_t) __THROW;  
  66. #define WORD_COPY_FWD(dst_bp, src_bp, nbytes_left, nbytes)            /  
  67.   do                                          /  
  68.     {                                         /  
  69.       if (src_bp % OPSIZ == 0)                            /  
  70.     _wordcopy_fwd_aligned (dst_bp, src_bp, (nbytes) / OPSIZ);         /  
  71.       else                                    /  
  72.     _wordcopy_fwd_dest_aligned (dst_bp, src_bp, (nbytes) / OPSIZ);        /  
  73.       src_bp += (nbytes) & -OPSIZ;                        /  
  74.       dst_bp += (nbytes) & -OPSIZ;                        /  
  75.       (nbytes_left) = (nbytes) % OPSIZ;                       /  
  76.     } while (0)  
  77. /* 向后复制:从SRC_END_PTR中复制最多NBYTES_TO_COPY个字节到DST_END_PTR中,复制 
  78.     从指针前面的字(为op_t类型)的右端开始,并且向着更小的地址方向前进。可以利用DST_END_PTR 
  79.     已经对齐到OPSIZ的倍数。如果不是所有的字节都能顺利的复制,剩下的字节数保存到 
  80.     NBYTES_REMAINING中,否则存入0 */  
  81. extern void _wordcopy_bwd_aligned (long intlong intsize_t) __THROW;  
  82. extern void _wordcopy_bwd_dest_aligned (long intlong intsize_t) __THROW;  
  83. #define WORD_COPY_BWD(dst_ep, src_ep, nbytes_left, nbytes)            /  
  84.   do                                          /  
  85.     {                                         /  
  86.       if (src_ep % OPSIZ == 0)                            /  
  87.     _wordcopy_bwd_aligned (dst_ep, src_ep, (nbytes) / OPSIZ);         /  
  88.       else                                    /  
  89.     _wordcopy_bwd_dest_aligned (dst_ep, src_ep, (nbytes) / OPSIZ);        /  
  90.       src_ep -= (nbytes) & -OPSIZ;                        /  
  91.       dst_ep -= (nbytes) & -OPSIZ;                        /  
  92.       (nbytes_left) = (nbytes) % OPSIZ;                       /  
  93.     } while (0)  
  94. /* 进入展开循环的门槛值  */  
  95. #define OP_T_THRES  16  

 

 

[cpp] view plaincopy
  1. /* pagecopy.h -- 按页方式来复制的宏;用在memcpy和memmove中  */  
  2. /* 本文件中定义的宏: 
  3.    PAGE_COPY_FWD_MAYBE (dstp, srcp, nbytes_left, nbytes) 
  4.     由WORD_COPY_FWD以及其他的函数来调用,指针至少要是字对齐的。这将会检查虚页复制是否能 
  5.     执行、是否应该执行、以及如果能执行的话则执行它 
  6.     依赖于系统的pagecopy.h文件应该定义以下宏,然后包含本文件: 
  7.    PAGE_COPY_THRESHOLD 
  8.    -- 值得使用按页复制策略的最小字节数 
  9.    PAGE_SIZE 
  10.    -- 页的大小 
  11.    PAGE_COPY_FWD (dstp, srcp, nbytes_left, nbytes) 
  12.    -- 执行虚页复制操作的宏。指针要对齐到PAGE_SIZE个字节的边界上 
  13. */  
  14. #if PAGE_COPY_THRESHOLD  
  15. #include <assert.h>  
  16. #define PAGE_COPY_FWD_MAYBE(dstp, srcp, nbytes_left, nbytes)              /  
  17.   do                                          /  
  18.     {                                         /  
  19.       if ((nbytes) >= PAGE_COPY_THRESHOLD &&                   /  
  20.       PAGE_OFFSET ((dstp) - (srcp)) == 0)                     /  
  21.     {                                     /  
  22.       /* 要复制的字节数超过内核用于复制虚拟页的VM操作的门槛值,且源地址         / 
  23.          和目标地址有同样的对齐方式 */    /  
  24.       size_t nbytes_before = PAGE_OFFSET (-(dstp));               /  
  25.       if (nbytes_before != 0)                         /  
  26.         {                                     /  
  27.           /* 首先复制第一页前面的各个字  */     /  
  28.           WORD_COPY_FWD (dstp, srcp, nbytes_left, nbytes_before);         /  
  29.           assert (nbytes_left == 0);                      /  
  30.           nbytes -= nbytes_before;                        /  
  31.         }                                     /  
  32.       PAGE_COPY_FWD (dstp, srcp, nbytes_left, nbytes);            /  
  33.     }                                     /  
  34.     } while (0)  
  35. /* 页大小总是2的幂,这样我们就可以避免模除法运算  */  
  36. #define PAGE_OFFSET(n)  ((n) & (PAGE_SIZE - 1))  
  37. #else  
  38. #define PAGE_COPY_FWD_MAYBE(dstp, srcp, nbytes_left, nbytes)   
  39. #endif  

 

 

[cpp] view plaincopy
  1. /* memcpy.c:memcpy函数的实现  */  
  2. #include <string.h>  
  3. #include <memcopy.h>  /* 包含了字节复制函数BYTE_COPY_FWD和字复制函数WORD_COPY_FWD */  
  4. #include <pagecopy.h>  /* 包含内存页复制函数PAGE_COPY_FWD_MAYBE */  
  5. #undef memcpy  
  6. /* 从src中复制len个字节的内容到dst中  */  
  7. void *  
  8. memcpy (dstpp, srcpp, len)  
  9.      void *dstpp;  
  10.      const void *srcpp;  
  11.      size_t len;  
  12. {  
  13.   unsigned long int dstp = (long int) dstpp;  
  14.   unsigned long int srcp = (long int) srcpp;  
  15.   /* 从开始复制到末尾 */  
  16.   /* 如果len足够长,使用字复制方式(一个字为long类型,一般占4个字节) */  
  17.   if (len >= OP_T_THRES)  
  18.     {  
  19.       /* 复制开头的几个字节,以使dstp对齐到字的边界 */  
  20.       len -= (-dstp) % OPSIZ;  
  21.       BYTE_COPY_FWD (dstp, srcp, (-dstp) % OPSIZ); /* 字节复制方式 */  
  22.       /* 通过虚拟地址操作,从srcp中复制尽可能多的页到dstp中 */  
  23.       PAGE_COPY_FWD_MAYBE (dstp, srcp, len, len); /* 页复制方式 */  
  24.       /* 利用对齐的dstp,采用字复制方式从srcp复制到dstp。剩余的字节数放在第三个实参中, 
  25.             例如放在len中。这个数字可能在不同的机器有不同的值 */  
  26.       WORD_COPY_FWD (dstp, srcp, len, len);  
  27.       /* 复制剩下的尾部几个字节 */  
  28.     }  
  29.   /* 还有剩下的几个字节,使用字节内存操作  */  
  30.   BYTE_COPY_FWD (dstp, srcp, len);  
  31.   return dstpp;  
  32. }  
  33. libc_hidden_builtin_def (memcpy)  

 

 

[cpp] view plaincopy
  1. /* memmove.c:memmove函数的实现 */  
  2. #include <string.h>  
  3. #include <memcopy.h>  /* 包含了字节复制函数BYTE_COPY_FWD和字复制函数WORD_COPY_FWD */  
  4. #include <pagecopy.h>  /* 包含内存页复制函数PAGE_COPY_FWD_MAYBE */  
  5. /* 所有这些都是为了在定义了一些东西后bcopy.c能包含本文件 */  
  6. #ifndef a1  
  7. #define a1  dest    /* 第一个实参是dest */  
  8. #define a1const  
  9. #define a2  src     /* 第二个实参是src  */  
  10. #define a2const const  
  11. #undef memmove  
  12. #endif  
  13. #if !defined(RETURN) || !defined(rettype)  
  14. #define RETURN(s)   return (s)  /* 返回dest  */  
  15. #define rettype     void *  
  16. #endif  
  17. /* 从SRC中复制LEN个字节的内容到DEST中,保证对重叠字符串(即SRC与DEST共用存储空间)有正确的行为 */  
  18. rettype  
  19. memmove (a1, a2, len)  
  20.      a1const void *a1;  
  21.      a2const void *a2;  
  22.      size_t len;  
  23. {  
  24.   unsigned long int dstp = (long int) dest;  
  25.   unsigned long int srcp = (long int) src;  
  26.   /* 这个测试使得向前复制代码一旦可能就能被使用,减少工作集 */  
  27.   if (dstp - srcp >= len)    /* *Unsigned* compare!  */  
  28.     {  
  29.       /* 从开始复制到末尾 */  
  30.       /* 如果len足够长,使用字复制方式(一个字为long类型,一般占4个字节) */  
  31.       if (len >= OP_T_THRES)  
  32.     {  
  33.       /* 复制开头的几个字节,以使dstp对齐到字的边界 */  
  34.       len -= (-dstp) % OPSIZ;  
  35.       BYTE_COPY_FWD (dstp, srcp, (-dstp) % OPSIZ); /* 字节复制方式 */  
  36.       /* 通过虚拟地址操作,从srcp中复制尽可能多的页到dstp中 */  
  37.       PAGE_COPY_FWD_MAYBE (dstp, srcp, len, len); /* 页复制方式 */  
  38.       /* 利用对齐的dstp,采用字复制方式从srcp复制到dstp。剩余的字节数放在第三个实参中, 
  39.             例如放在len中。这个数字可能在不同的机器有不同的值 */  
  40.       WORD_COPY_FWD (dstp, srcp, len, len);  
  41.       /* 复制剩下的尾部几个字节 */  
  42.     }  
  43.       /* 还有剩下的几个字节,使用字节内存操作 */  
  44.       BYTE_COPY_FWD (dstp, srcp, len);  
  45.     }  
  46.   else  
  47.     {  
  48.       /* 从开始复制到末尾  */  
  49.       srcp += len;  
  50.       dstp += len;  
  51.       /* 如果len足够长,使用字复制方式(一个字为long类型,一般占4个字节) */  
  52.       if (len >= OP_T_THRES)  
  53.     {  
  54.       /* 复制开头的几个字节,以使dstp对齐到字的边界 */  
  55.       len -= dstp % OPSIZ;  
  56.       BYTE_COPY_BWD (dstp, srcp, dstp % OPSIZ);  
  57.       /* 利用对齐的dstp,采用字复制方式从srcp复制到dstp。剩余的字节数放在第三个实参中, 
  58.             例如放在len中。这个数字可能在不同的机器有不同的值 */  
  59.       WORD_COPY_BWD (dstp, srcp, len, len);  
  60.       /* 复制剩下的尾部几个字节 */  
  61.     }  
  62.       /* 还有剩下的几个字节,使用字节内存操作 */  
  63.       BYTE_COPY_BWD (dstp, srcp, len);  
  64.     }  
  65.   RETURN (dest);  
  66. }  
  67. #ifndef memmove  
  68. libc_hidden_builtin_def (memmove)  
  69. #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类似。

 

[cpp] view plaincopy
  1. /* memchr.c:memchr函数的实现 */  
  2. #ifdef HAVE_CONFIG_H  
  3. #include <config.h>  
  4. #endif  
  5. #undef __ptr_t  
  6. /* 标准C++或标准C中通用指针为void*类型 */  
  7. #if defined (__cplusplus) || (defined (__STDC__) && __STDC__)  
  8. # define __ptr_t void *  
  9. #else /* 传统C中通用指针为char*类型 */  
  10. # define __ptr_t char *  
  11. #endif  
  12. #if defined _LIBC  
  13. # include <string.h>  
  14. # include <memcopy.h>  
  15. #else  
  16. # define reg_char char  
  17. #endif  
  18. #if HAVE_STDLIB_H || defined _LIBC  
  19. # include <stdlib.h>  
  20. #endif  
  21. #if HAVE_LIMITS_H || defined _LIBC  
  22. # include <limits.h>  
  23. #endif  
  24. #define LONG_MAX_32_BITS 2147483647  
  25. #ifndef LONG_MAX  
  26. #define LONG_MAX LONG_MAX_32_BITS  
  27. #endif  
  28. #include <sys/types.h>  
  29. #if HAVE_BP_SYM_H || defined _LIBC  
  30. #include <bp-sym.h>  
  31. #else  
  32. # define BP_SYM(sym) sym  
  33. #endif  
  34. #undef memchr  
  35. #undef __memchr  
  36. /* 在S的前N个字节中搜索C的第一次出现  */  
  37. __ptr_t  
  38. __memchr (s, c_in, n)  
  39.      const __ptr_t s;  
  40.      int c_in;  
  41.      size_t n;  
  42. {  
  43.   const unsigned char *char_ptr;  
  44.   const unsigned long int *longword_ptr;  
  45.   unsigned long int longword, magic_bits, charmask;  
  46.   unsigned reg_char c;  
  47.   c = (unsigned char) c_in;  
  48.   /* 通过一次读取一个字符来处理开头的几个字符,直到char_ptr中的值对齐到一个long型字的边界, 
  49.       即直到char_ptr中的值是long的字节数(通常为4)的倍数 */  
  50.   for (char_ptr = (const unsigned char *) s;  
  51.        n > 0 && ((unsigned long int) char_ptr  
  52.          & (sizeof (longword) - 1)) != 0;  
  53.        --n, ++char_ptr)  
  54.     if (*char_ptr == c)   /* 若到达字符c处,则直接返回其指针 */  
  55.       return (__ptr_t) char_ptr;  
  56.   /* 所有这些说明性的注释使用4字节的long型字,但本算法同样也可以应用于8字节的long型字 */  
  57.   longword_ptr = (unsigned long int *) char_ptr;  
  58.   /* magic_bits的第8,16,24,31位为0,称这些位为“洞”。注意每个字节的左边有一个洞, 
  59.       在最后的位置上也有一个洞。 
  60.      bits:  01111110 11111110 11111110 11111111 
  61.       比特1确保进位能传播到后面的比特0上,比特0则提供洞,以便让进位陷进去  */  
  62.   if (sizeof (longword) != 4 && sizeof (longword) != 8)  
  63.     abort ();  
  64. #if LONG_MAX <= LONG_MAX_32_BITS  
  65.   magic_bits = 0x7efefeff;  
  66. #else  
  67.   magic_bits = ((unsigned long int) 0x7efefefe << 32) | 0xfefefeff;  
  68. #endif  
  69.   /* 设置一个长整型字,其每个字节都是字符c */  
  70.   charmask = c | (c << 8);  
  71.   charmask |= charmask << 16;  
  72. #if LONG_MAX > LONG_MAX_32_BITS  
  73.   charmask |= charmask << 32;  
  74. #endif  
  75.   /* 这里我们不使用传统的对每个字符都进行测试的循环,而是一次测试一个long型字。技巧性的部分 
  76.       是测试当前long型字的各个字节是否为0 */  
  77.   while (n >= sizeof (longword))  
  78.     {      
  79.       /* longword中有一个字节为C,恰好等价于longword ^ charmask中有一个字节为0 */  
  80.       longword = *longword_ptr++ ^ charmask;  
  81.       /* 让longword加上魔数magic_bits  */  
  82.       if ((((longword + magic_bits)  
  83.         /* 设置那些通过加法而未改变的位 */  
  84.         ^ ~longword)  
  85.        /* 只需看这些洞。如果任何的洞位都没有改变,最有可能的是有一个字节值为C或者到达终止符处(没找到C) */  
  86.        & ~magic_bits) != 0)  
  87.     {  
  88.       /* 长整型字的哪个字节为C或0?如果都不是,则是一个非预期情况,继续搜索 */  
  89.       const unsigned char *cp = (const unsigned char *) (longword_ptr - 1);  
  90.       if (cp[0] == c)  
  91.         return (__ptr_t) cp;  
  92.       if (cp[1] == c)  
  93.         return (__ptr_t) &cp[1];  
  94.       if (cp[2] == c)  
  95.         return (__ptr_t) &cp[2];  
  96.       if (cp[3] == c)  
  97.         return (__ptr_t) &cp[3];  
  98. #if LONG_MAX > 2147483647      /* 如果long类型是8个字节,则还有4个字节需要判断 */  
  99.       if (cp[4] == c)  
  100.         return (__ptr_t) &cp[4];  
  101.       if (cp[5] == c)  
  102.         return (__ptr_t) &cp[5];  
  103.       if (cp[6] == c)  
  104.         return (__ptr_t) &cp[6];  
  105.       if (cp[7] == c)  
  106.         return (__ptr_t) &cp[7];  
  107. #endif  
  108.     }  
  109.       n -= sizeof (longword);  
  110.     }  
  111.   /* 循环完如果还剩下几个字节,则继承搜索这剩下的几个字节 */  
  112.   char_ptr = (const unsigned char *) longword_ptr;  
  113.   while (n-- > 0)  
  114.     {  
  115.       if (*char_ptr == c)  
  116.     return (__ptr_t) char_ptr;  
  117.       else  
  118.     ++char_ptr;  
  119.     }  
  120.   return 0;  
  121. }  
  122. #ifdef weak_alias  
  123. weak_alias (__memchr, BP_SYM (memchr))  
  124. #endif  
  125. libc_hidden_builtin_def (memchr)  

 

    12、内存块比较memcmp,wmemcmp:对两个内存块的前N个字节进行比较。比较也是使用字(unsigned long型)的比较方式,以加快搜索速度。采用的策略是先比较开头的几个字节,以使块指针对齐到字的边界,再用memcmp_common_alignment(两个内存块都对齐的情况)或memcmp_not_common_alignment(一个内存块对齐,而另一个没有对齐)按字进行快速的比较,最后对剩下的几个字节进行比较。代码就不再解剖了,涉及到大量的字操作,以及用MERGE进行字合并(这需要考虑到机器的字节序)。     
    13、内存块设置memset,wmemset:将内存块的前LEN个字节设置为字符C。也是采用字的方式来进行快速地写入。先设置了一个字cccc,其每个字节都是字符C。为了加快写入速度,每循环一次就写入8个cccc,最后对剩下的几个字节写入C。

 

[cpp] view plaincopy
  1. /* memset.c:memset函数的实现  */  
  2. #include <string.h>  
  3. #include <memcopy.h>  
  4. #undef memset  
  5. /* 将内存块DST的前LEN个字节设置为字符C */  
  6. void *  
  7. memset (dstpp, c, len)  
  8.      void *dstpp;  
  9.      int c;  
  10.      size_t len;  
  11. {  
  12.   long int dstp = (long int) dstpp;  
  13.   if (len >= 8)  
  14.     {  
  15.       size_t xlen;  
  16.       op_t cccc;  
  17.         
  18.       /* 设置一个长整型字,其每个字节都是字符c */  
  19.       cccc = (unsigned char) c;  
  20.       cccc |= cccc << 8;  
  21.       cccc |= cccc << 16;  
  22.       if (OPSIZ > 4)  
  23.       /* 移位操作分两步,以避免当long为32位时出现警告 */  
  24.     cccc |= (cccc << 16) << 16;  
  25.      /* 把dstp对齐到字的边界,开头的几个字节要设置为C,在这个对齐循环中无需 
  26.          测试LEN是否等于0 */  
  27.       while (dstp % OPSIZ != 0)  
  28.     {  
  29.       ((byte *) dstp)[0] = c;  
  30.       dstp += 1;  
  31.       len -= 1;  
  32.     }  
  33.       /* 每次迭代中写8个op_t型的字,直到剩下不到8个字为止 */  
  34.       xlen = len / (OPSIZ * 8); /* 计算迭代次数 */  
  35.       while (xlen > 0)  
  36.     {  
  37.       ((op_t *) dstp)[0] = cccc;  
  38.       ((op_t *) dstp)[1] = cccc;  
  39.       ((op_t *) dstp)[2] = cccc;  
  40.       ((op_t *) dstp)[3] = cccc;  
  41.       ((op_t *) dstp)[4] = cccc;  
  42.       ((op_t *) dstp)[5] = cccc;  
  43.       ((op_t *) dstp)[6] = cccc;  
  44.       ((op_t *) dstp)[7] = cccc;  
  45.       dstp += 8 * OPSIZ;  
  46.       xlen -= 1;  
  47.     }  
  48.       len %= OPSIZ * 8; /* 计算剩下的字节数 */  
  49.       /* 每次迭代写1个字,直到剩下不到OPSIZ个字节为止 */  
  50.       xlen = len / OPSIZ;  /* 计算迭代次数 */  
  51.       while (xlen > 0)  
  52.     {  
  53.       ((op_t *) dstp)[0] = cccc;  
  54.       dstp += OPSIZ;  
  55.       xlen -= 1;  
  56.     }  
  57.       len %= OPSIZ;  
  58.     }  
  59.   /* 写入最后剩下的几个字节 */  
  60.   while (len > 0)  
  61.     {  
  62.       ((byte *) dstp)[0] = c;  
  63.       dstp += 1;  
  64.       len -= 1;  
  65.     }  
  66.   return dstpp;  
  67. }  
  68. libc_hidden_builtin_def (memset)  

 

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表