您好,欢迎来到微智科技网。
搜索
您的当前位置:首页C标准库源码解剖(6):字符串处理函数string.h和wchar.h(续)

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

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

分类: C 2009-10-08 12:56 288人阅读 评论(0) 收藏 举报

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

view plaincopy to clipboardprint?

1. /* strcoll.c:strcoll函数的实现 */ 2. #include 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

/* strcoll.c:strcoll函数的实现 */#include #ifndef STRING_TYPE# define STRING_TYPE char# define STRCOLL strcoll# define STRCOLL_L __strcoll_l# define USE_HIDDEN_DEF#endif#include \"../locale/localeinfo.h\"intSTRCOLL (s1, s2) const STRING_TYPE *s1; const STRING_TYPE *s2;{ return STRCOLL_L (s1, s2, _NL_CURRENT_LOCALE);}#ifdef USE_HIDDEN_DEFlibc_hidden_def (STRCOLL) view plaincopy to clipboardprint? 1. /* strxfrm.c:strxfrm函数的实现 */ 2. #include

3. #include 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. }

/* strxfrm.c:strxfrm函数的实现 */#include #include #ifndef STRING_TYPE# define STRING_TYPE char# define STRXFRM strxfrm# define STRXFRM_L __strxfrm_l#endifsize_tSTRXFRM (STRING_TYPE *dest, const STRING_TYPE *src,{ return STRXFRM_L (dest, src, n, _NL_CURRENT_LOCAL} 9、错误消息报告strerror:获取错误码errnum的字符串描述,在下一次调用strerror之前这个字符串存储空间不能修改,对这个空间进行写操作会导致未定义的行为。若获取没有成功,则使用errno全局变量(或全局宏)中的错误码来获取错误消息。 view plaincopy to clipboardprint?

1. /* strerror.c:strerror函数的实现 */ 2. #include /* 有很多内部接口 */ 3. #include 4. #include

5. #include /* 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. }

/* strerror.c:strerror函数的实现 */#include /* 有很多内部接口 */#include #include #include /* errno中保存了程序的错误码 *//* 返回错误码errnum的字符串描述,在下一次调用strerror之 空间不能修改,对这个空间进行写操作会导致未定义的行为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; /* 否则获取errno中保存的程序错误码,用缓冲区buf来存储 saved_errno = errno; 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,这些接口都是以宏的形式提供的。 view plaincopy to clipboardprint? 1. /* memcopy.h -- 在内存复制函数中使用的一些定义 */ 2. /* 内存函数的复制策略是:

3. 1、复制字节,直到目标指针被对齐。

4. 2、在展开的循环中复制字。如果源指针和目标指针不是用

5. 同一种方式对齐,则使用字内存操作,但在写之前要对两个读取的字进行移位

和合并

6. 3、复制剩下的几个字节

7. 在至少有10个寄存器用来给GCC使用的处理器上,这是非常快速的,并且能

在一条指令中使用 8. reg+const来访问内存 */ 9. #include 10. #include 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_t

o_copy)

15. WORD_COPY_BWD(dst_end_ptr, src_end_ptr, nbytes_remaining, nbytes_t

o_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 */

. extern void _wordcopy_fwd_aligned (long int, long int, size_t) __THROW; 65. extern void _wordcopy_fwd_dest_aligned (long int, long int, size_t) __THRO

W;

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 int, long int, size_t) __THROW; 82. extern void _wordcopy_bwd_dest_aligned (long int, long int, size_t) __THR

OW;

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 /

. _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

/* memcopy.h -- 在内存复制函数中使用的一些定义 *//* 内存函数的复制策略是: 1、复制字节,直到目标指针被对齐。 2、在展开的循环中复制字。如果源指针和目标指针不是用 同一种方式对齐,则使用字内存操作,但在写之前要对两 3、复制剩下的几个字节 在至少有10个寄存器用来给GCC使用的处理器上,这是非 reg+const来访问内存 */#include #include /* 在本文件中定义的宏有: BYTE_COPY_FWD(dst_beg_ptr, src_beg_ptr, nbytes_t BYTE_COPY_BWD(dst_end_ptr, src_end_ptr, nbytes_t WORD_COPY_FWD(dst_beg_ptr, src_beg_ptr, nbytes_r WORD_COPY_BWD(dst_end_ptr, src_end_ptr, nbytes_r MERGE(old_word, sh_1, new_word, sh_2)*//* 用于对齐的内存操作类型,正常时它应该是能一次装载和存 view plaincopy to clipboardprint? 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

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

/* pagecopy.h -- 按页方式来复制的宏;用在memcpy和memm/* 本文件中定义的宏: PAGE_COPY_FWD_MAYBE (dstp, srcp, nbytes_left, nb 由WORD_COPY_FWD以及其他的函数来调用,指针至少要是字 执行、是否应该执行、以及如果能执行的话则执行它 依赖于系统的pagecopy.h文件应该定义以下宏,然后包含 PAGE_COPY_THRESHOLD -- 值得使用按页复制策略的最小字节数 PAGE_SIZE -- 页的大小 PAGE_COPY_FWD (dstp, srcp, nbytes_left, nbytes) -- 执行虚页复制操作的宏。指针要对齐到PAGE_SIZE个字节*/#if PAGE_COPY_THRESHOLD#include #define PAGE_COPY_FWD_MAYBE(dstp, srcp, nbytes_left do { view plaincopy to clipboardprint? 1. /* memcpy.c:memcpy函数的实现 */ 2. #include

3. #include /* 包含了字节复制函数BYTE_COPY_FWD和字复制函

数WORD_COPY_FWD */

4. #include /* 包含内存页复制函数

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)

/* memcpy.c:memcpy函数的实现 */#include #include /* 包含了字节复制函数BYTE_COPY#include /* 包含内存页复制函数PAGE_COP#undef memcpy/* 从src中复制len个字节的内容到dst中 */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; /* 从开始复制到末尾 */ /* 如果len足够长,使用字复制方式(一个字为long类型, if (len >= OP_T_THRES) { view plaincopy to clipboardprint? 1. /* memmove.c:memmove函数的实现 */ 2. #include

3. #include /* 包含了字节复制函数BYTE_COPY_FWD和字复制函

数WORD_COPY_FWD */

4. #include /* 包含内存页复制函数

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); . }

65. RETURN (dest); 66. }

67. #ifndef memmove

68. libc_hidden_builtin_def (memmove) 69. #endif

/* memmove.c:memmove函数的实现 */#include #include /* 包含了字节复制函数BYTE_COPY#include /* 包含内存页复制函数PAGE_COP/* 所有这些都是为了在定义了一些东西后bcopy.c能包含本文#ifndefa1#definea1dest/* 第一个实参是dest */#definea1const#definea2src /* 第二个实参是src */#definea2constconst#undef memmove#endif#if!defined(RETURN) || !defined(rettype)#defineRETURN(s)return (s)/* 返回dest#definerettypevoid *#endif/* 从SRC中复制LEN个字节的内容到DEST中,保证对重叠字符串rettype 解释: (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类似。 view plaincopy to clipboardprint? 1. /* memchr.c:memchr函数的实现 */ 2. #ifdef HAVE_CONFIG_H 3. #include 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 14. # include 15. #else

16. # define reg_char char 17. #endif

18. #if HAVE_STDLIB_H || defined _LIBC 19. # include 20. #endif

21. #if HAVE_LIMITS_H || defined _LIBC 22. # include 23. #endif

24. #define LONG_MAX_32_BITS 21474837 25. #ifndef LONG_MAX

26. #define LONG_MAX LONG_MAX_32_BITS 27. #endif

28. #include

29. #if HAVE_BP_SYM_H || defined _LIBC 30. #include 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 ();

. #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?如果都不是,则是一个非预期情况,继续

搜索 */

. 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 > 21474837 /* 如果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)

/* memchr.c:memchr函数的实现 */#ifdef HAVE_CONFIG_H#include #endif#undef __ptr_t/* 标准C++或标准C中通用指针为void*类型 */#if defined (__cplusplus) || (defined (__STDC__) &&# define __ptr_t void *#else /* 传统C中通用指针为char*类型 */# define __ptr_t char *#endif#if defined _LIBC# include # include #else# define reg_char char#endif#if HAVE_STDLIB_H || defined _LIBC 12、内存块比较memcmp,wmemcmp:对两个内存块的前N个字节进行比较。比较也是使用字(unsigned long型)的比较方式,以加快搜索速度。采用的策略是先比较开头的几个字节,以使块指针对齐到字的边界,再用memcmp_common_alignment(两个内存块都对齐的情况)或memcmp_not_common_alignment(一个内存块对齐,而另一个没有对齐)按字进行快速的比较,最后对剩下的几个字节进行比较。代码就不再解剖了,涉及到大量的字操作,以及用MERGE进行字合并(这需要考虑到机器的字节序)。

13、内存块设置memset,wmemset:将内存块的前LEN个字节设置为字符C。也是采用字的方式来进行快速地写入。先设置了一个字cccc,其每个字节都是字符C。为了加快写入速度,每循环一次就写入8个cccc,最后对剩下的几个字节写入C。 view plaincopy to clipboardprint?

1. /* memset.c:memset函数的实现 */ 2. #include 3. #include 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; . len -= 1; 65. }

66. return dstpp; 67. }

68. libc_hidden_builtin_def (memset)

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- 7swz.com 版权所有 赣ICP备2024042798号-8

违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务