您的位置:首页 > 其它

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

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

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


/* strxfrm.c:strxfrm函数的实现  */
#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全局变量(或全局宏)中的错误码来获取错误消息。

/* strerror.c:strerror函数的实现  */
#include <libintl.h> /* 有很多内部接口 */
#include <stdio.h>
#include <string.h>
#include <errno.h>   /* 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;
if (buf == NULL)
buf = malloc (1024);  /* buf是一个全局缓冲区 */
__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,这些接口都是以宏的形式提供的。

/* memcopy.h -- 在内存复制函数中使用的一些定义  */
/* 内存函数的复制策略是:
1、复制字节,直到目标指针被对齐。
2、在展开的循环中复制字。如果源指针和目标指针不是用
同一种方式对齐,则使用字内存操作,但在写之前要对两个读取的字进行移位和合并
3、复制剩下的几个字节
在至少有10个寄存器用来给GCC使用的处理器上,这是非常快速的,并且能在一条指令中使用
reg+const来访问内存  */
#include <sys/cdefs.h>
#include <endian.h>
/* 在本文件中定义的宏有:
BYTE_COPY_FWD(dst_beg_ptr, src_beg_ptr, nbytes_to_copy)
BYTE_COPY_BWD(dst_end_ptr, src_end_ptr, nbytes_to_copy)
WORD_COPY_FWD(dst_beg_ptr, src_beg_ptr, nbytes_remaining, nbytes_to_copy)
WORD_COPY_BWD(dst_end_ptr, src_end_ptr, nbytes_remaining, nbytes_to_copy)
MERGE(old_word, sh_1, new_word, sh_2)
*/
/* 用于对齐的内存操作类型,正常时它应该是能一次装载和存储的最大类型 */
#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
/* 向前复制:从SRC_BP中精确地复制NBTYES个字节到DST_BP中,无需对指针的对齐作任何假设  */
#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)
/* 向后复制:从SRC_END_PTR中精确地复制NBTYTES_TO_COPY个字节到DST_END_PTR中,
复制从指针前面的字节右端开始,并且向着更小的地址方向前进。无需对指针的对齐作任何假设 */
#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)
/* 向前复制:从SRC_BP中复制最多NBYTES个字节到DST_BP中,假设DST_BP对齐到OPSIZ的倍数。
如果不是所有的字节都能顺利的复制,剩下的字节数保存到NBYTES_LEFT中,否则存入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)
/* 向后复制:从SRC_END_PTR中复制最多NBYTES_TO_COPY个字节到DST_END_PTR中,复制
从指针前面的字(为op_t类型)的右端开始,并且向着更小的地址方向前进。可以利用DST_END_PTR
已经对齐到OPSIZ的倍数。如果不是所有的字节都能顺利的复制,剩下的字节数保存到
NBYTES_REMAINING中,否则存入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


/* pagecopy.h -- 按页方式来复制的宏;用在memcpy和memmove中  */
/* 本文件中定义的宏:
PAGE_COPY_FWD_MAYBE (dstp, srcp, nbytes_left, nbytes)
由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 <assert.h>
#define PAGE_COPY_FWD_MAYBE(dstp, srcp, nbytes_left, nbytes)		      /
do									      /
{									      /
if ((nbytes) >= PAGE_COPY_THRESHOLD &&				      /
PAGE_OFFSET ((dstp) - (srcp)) == 0) 				      /
{								      /
/* 要复制的字节数超过内核用于复制虚拟页的VM操作的门槛值,且源地址	      /
和目标地址有同样的对齐方式 */    /
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)
/* 页大小总是2的幂,这样我们就可以避免模除法运算  */
#define PAGE_OFFSET(n)	((n) & (PAGE_SIZE - 1))
#else
#define PAGE_COPY_FWD_MAYBE(dstp, srcp, nbytes_left, nbytes)
#endif


/* memcpy.c:memcpy函数的实现  */
#include <string.h>
#include <memcopy.h>  /* 包含了字节复制函数BYTE_COPY_FWD和字复制函数WORD_COPY_FWD */
#include <pagecopy.h>  /* 包含内存页复制函数PAGE_COPY_FWD_MAYBE */
#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类型,一般占4个字节) */
if (len >= OP_T_THRES)
{
/* 复制开头的几个字节,以使dstp对齐到字的边界 */
len -= (-dstp) % OPSIZ;
BYTE_COPY_FWD (dstp, srcp, (-dstp) % OPSIZ); /* 字节复制方式 */
/* 通过虚拟地址操作,从srcp中复制尽可能多的页到dstp中 */
PAGE_COPY_FWD_MAYBE (dstp, srcp, len, len); /* 页复制方式 */
/* 利用对齐的dstp,采用字复制方式从srcp复制到dstp。剩余的字节数放在第三个实参中,
例如放在len中。这个数字可能在不同的机器有不同的值 */
WORD_COPY_FWD (dstp, srcp, len, len);
/* 复制剩下的尾部几个字节 */
}
/* 还有剩下的几个字节,使用字节内存操作  */
BYTE_COPY_FWD (dstp, srcp, len);
return dstpp;
}
libc_hidden_builtin_def (memcpy)


/* memmove.c:memmove函数的实现 */
#include <string.h>
#include <memcopy.h>  /* 包含了字节复制函数BYTE_COPY_FWD和字复制函数WORD_COPY_FWD */
#include <pagecopy.h>  /* 包含内存页复制函数PAGE_COPY_FWD_MAYBE */
/* 所有这些都是为了在定义了一些东西后bcopy.c能包含本文件 */
#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
/* 从SRC中复制LEN个字节的内容到DEST中,保证对重叠字符串(即SRC与DEST共用存储空间)有正确的行为 */
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)	/* *Unsigned* compare!  */
{
/* 从开始复制到末尾 */
/* 如果len足够长,使用字复制方式(一个字为long类型,一般占4个字节) */
if (len >= OP_T_THRES)
{
/* 复制开头的几个字节,以使dstp对齐到字的边界 */
len -= (-dstp) % OPSIZ;
BYTE_COPY_FWD (dstp, srcp, (-dstp) % OPSIZ); /* 字节复制方式 */
/* 通过虚拟地址操作,从srcp中复制尽可能多的页到dstp中 */
PAGE_COPY_FWD_MAYBE (dstp, srcp, len, len); /* 页复制方式 */
/* 利用对齐的dstp,采用字复制方式从srcp复制到dstp。剩余的字节数放在第三个实参中,
例如放在len中。这个数字可能在不同的机器有不同的值 */
WORD_COPY_FWD (dstp, srcp, len, len);
/* 复制剩下的尾部几个字节 */
}
/* 还有剩下的几个字节,使用字节内存操作 */
BYTE_COPY_FWD (dstp, srcp, len);
}
else
{
/* 从开始复制到末尾  */
srcp += len;
dstp += len;
/* 如果len足够长,使用字复制方式(一个字为long类型,一般占4个字节) */
if (len >= OP_T_THRES)
{
/* 复制开头的几个字节,以使dstp对齐到字的边界 */
len -= dstp % OPSIZ;
BYTE_COPY_BWD (dstp, srcp, dstp % OPSIZ);
/* 利用对齐的dstp,采用字复制方式从srcp复制到dstp。剩余的字节数放在第三个实参中,
例如放在len中。这个数字可能在不同的机器有不同的值 */
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类似。

/* memchr.c:memchr函数的实现 */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#undef __ptr_t
/* 标准C++或标准C中通用指针为void*类型 */
#if defined (__cplusplus) || (defined (__STDC__) && __STDC__)
# define __ptr_t void *
#else /* 传统C中通用指针为char*类型 */
# define __ptr_t char *
#endif
#if defined _LIBC
# include <string.h>
# include <memcopy.h>
#else
# define reg_char char
#endif
#if HAVE_STDLIB_H || defined _LIBC
# include <stdlib.h>
#endif
#if HAVE_LIMITS_H || defined _LIBC
# include <limits.h>
#endif
#define LONG_MAX_32_BITS 2147483647
#ifndef LONG_MAX
#define LONG_MAX LONG_MAX_32_BITS
#endif
#include <sys/types.h>
#if HAVE_BP_SYM_H || defined _LIBC
#include <bp-sym.h>
#else
# define BP_SYM(sym) sym
#endif
#undef memchr
#undef __memchr
/* 在S的前N个字节中搜索C的第一次出现  */
__ptr_t
__memchr (s, c_in, n)
const __ptr_t s;
int c_in;
size_t n;
{
const unsigned char *char_ptr;
const unsigned long int *longword_ptr;
unsigned long int longword, magic_bits, charmask;
unsigned reg_char c;
c = (unsigned char) c_in;
/* 通过一次读取一个字符来处理开头的几个字符,直到char_ptr中的值对齐到一个long型字的边界,
即直到char_ptr中的值是long的字节数(通常为4)的倍数 */
for (char_ptr = (const unsigned char *) s;
n > 0 && ((unsigned long int) char_ptr
& (sizeof (longword) - 1)) != 0;
--n, ++char_ptr)
if (*char_ptr == c)   /* 若到达字符c处,则直接返回其指针 */
return (__ptr_t) char_ptr;
/* 所有这些说明性的注释使用4字节的long型字,但本算法同样也可以应用于8字节的long型字 */
longword_ptr = (unsigned long int *) char_ptr;
/* magic_bits的第8,16,24,31位为0,称这些位为“洞”。注意每个字节的左边有一个洞,
在最后的位置上也有一个洞。
bits:  01111110 11111110 11111110 11111111
比特1确保进位能传播到后面的比特0上,比特0则提供洞,以便让进位陷进去  */
if (sizeof (longword) != 4 && sizeof (longword) != 8)
abort ();
#if LONG_MAX <= LONG_MAX_32_BITS
magic_bits = 0x7efefeff;
#else
magic_bits = ((unsigned long int) 0x7efefefe << 32) | 0xfefefeff;
#endif
/* 设置一个长整型字,其每个字节都是字符c */
charmask = c | (c << 8);
charmask |= charmask << 16;
#if LONG_MAX > LONG_MAX_32_BITS
charmask |= charmask << 32;
#endif
/* 这里我们不使用传统的对每个字符都进行测试的循环,而是一次测试一个long型字。技巧性的部分
是测试当前long型字的各个字节是否为0 */
while (n >= sizeof (longword))
{
/* longword中有一个字节为C,恰好等价于longword ^ charmask中有一个字节为0 */
longword = *longword_ptr++ ^ charmask;
/* 让longword加上魔数magic_bits  */
if ((((longword + magic_bits)
/* 设置那些通过加法而未改变的位 */
^ ~longword)
/* 只需看这些洞。如果任何的洞位都没有改变,最有可能的是有一个字节值为C或者到达终止符处(没找到C) */
& ~magic_bits) != 0)
{
/* 长整型字的哪个字节为C或0?如果都不是,则是一个非预期情况,继续搜索 */
const unsigned char *cp = (const unsigned char *) (longword_ptr - 1);
if (cp[0] == c)
return (__ptr_t) cp;
if (cp[1] == c)
return (__ptr_t) &cp[1];
if (cp[2] == c)
return (__ptr_t) &cp[2];
if (cp[3] == c)
return (__ptr_t) &cp[3];
#if LONG_MAX > 2147483647      /* 如果long类型是8个字节,则还有4个字节需要判断 */
if (cp[4] == c)
return (__ptr_t) &cp[4];
if (cp[5] == c)
return (__ptr_t) &cp[5];
if (cp[6] == c)
return (__ptr_t) &cp[6];
if (cp[7] == c)
return (__ptr_t) &cp[7];
#endif
}
n -= sizeof (longword);
}
/* 循环完如果还剩下几个字节,则继承搜索这剩下的几个字节 */
char_ptr = (const unsigned char *) longword_ptr;
while (n-- > 0)
{
if (*char_ptr == c)
return (__ptr_t) char_ptr;
else
++char_ptr;
}
return 0;
}
#ifdef weak_alias
weak_alias (__memchr, BP_SYM (memchr))
#endif
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。

/* memset.c:memset函数的实现  */
#include <string.h>
#include <memcopy.h>
#undef memset
/* 将内存块DST的前LEN个字节设置为字符C */
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;

/* 设置一个长整型字,其每个字节都是字符c */
cccc = (unsigned char) c;
cccc |= cccc << 8;
cccc |= cccc << 16;
if (OPSIZ > 4)
/* 移位操作分两步,以避免当long为32位时出现警告 */
cccc |= (cccc << 16) << 16;
/* 把dstp对齐到字的边界,开头的几个字节要设置为C,在这个对齐循环中无需
测试LEN是否等于0 */
while (dstp % OPSIZ != 0)
{
((byte *) dstp)[0] = c;
dstp += 1;
len -= 1;
}
/* 每次迭代中写8个op_t型的字,直到剩下不到8个字为止 */
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; /* 计算剩下的字节数 */
/* 每次迭代写1个字,直到剩下不到OPSIZ个字节为止 */
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)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: