CRT源码解析(三)字符串函数(2)
发表于 2006-05-22 11:52 AM 作者: tomato
CRT源码解析(三)
字符串函数(2)
0、代码
c++ 代码:
1、strlen
size_t strlen(const char *s);
strlen.asm中的定义:
asm 代码:
先判断是否aligned,若没有先aligned string
按int判断是否下一个4byte中有一个为0(类似memchr的算法)
asm 代码:
如果在这个int中找到一个char是0了,则分别
asm 代码:
依次je到相应的byte_0/byte_1/byte_2/byte_3去
tips:回顾一下memchr的实现,这俩实际是一样的。顺便再参考一下"Hacker’s Delight"的6-1 Find First 0-Byte就ok了
2、strchr & strrchr
char *strchr(const char *s, int c);
char *strrchr(const char *s, int c);
strchr.asm中:
asm 代码:
先把string给align了
然后弄一个int里面全是这个需要找的byte,判断找到或是遇到串尾的方法和memchr类似,判断原串中是否有一个byte是0和xor上需要找的byte后是否有0。找到后仍然和memchr一样的判断。
strrchr.asm中:
asm 代码:
先用repne scasb找到字符串尾,再std了用repnz scasb从后往前找,最后记得cld
tips:
strrchr中的
add ecx, 1
neg ecx
为什么不写成not ecx?
3、strcpy & strcat & strncpy & strncat
char *strcpy(char * restrict s1,
const char * restrict s2);
char *strncpy(char * restrict s1,
const char * restrict s2,
size_t n);
char *strcat(char * restrict s1,
const char * restrict s2);
char *strncat(char * restrict s1,
const char * restrict s2,
size_t n);
strcat.asm
asm 代码:
先align了,判断\0的方法同其他一样,所以这里只能一个个复制,不能用rep stosd,更别说sse2了
asm 代码:
strcat和strcpy实现一样,除了strcat先把dst走到了串尾,实际上strcpy在push了edi后就直接跳转到strcat的函数内了
strncpy.asm中的strncpy
strncat.asm中的strncat
看了前面那么多实现,这俩已经没有新意了
4、strset
strset.asm
asm 代码:
先repne scasb到串尾,得出长度,再rep stosb
5、strspn、strcspn、strpbrk
size_t strspn(const char *s1, const char *s2);
size_t strcspn(const char *s1, const char *s2);
char *strpbrk(const char *s1, const char *s2);
这3个实际实现大部分是一样的,就是判断是否找到和返回时略有不同,实现都在:strspn.asm中
预处理语句:
asm 代码:
同样的处理手法在前一篇文章的memcpy和memmove也用到了
asm 代码:
push 8个0,得到一个256bit全是0的map,将control字符串出现的所有byte都在map中置位:
asm 代码:
找string中第一个不在这个map中的byte:
asm 代码:
三个函数判断是否找到后的代码:
asm 代码:
6、strcmp & strncmp & strcoll
int strcmp(const char *s1, const char *s2);
int strncmp(const char *s1, const char *s2, size_t n);
int strcoll(const char *s1, const char *s2);
size_t strxfrm(char * restrict s1,
const char * restrict s2,
size_t n);
strcmp.asm
asm 代码:
先判断str1是不是4bytes的倍数,如果是,跳转dodwords,否则跳转dopartial
dodwords先读入4bytes到eax,然后从al、ah……的顺序一个个比较,不等跳donene,遇到字符串结束跳doneeq
dopartial先判断str1是不是2bytes的倍数,如果是跳doword,否则从edx(是str1)中一次取一个byte来比较
doword每次取2个bytes放在ax中比较
strncmp.c
c++ 代码:
strcoll.c
c++ 代码:
strxfrm.c
c++ 代码:
不懂locale,以后再来补充
tips:
1、donene中将eax置为1/-1的方法
asm 代码:
执行这一步前是cmp str1 str2的语句,如果str1 < str2会有CF = 1,否则CF = 0
2、在c语言实现中(比如strncmp.c),虽然参数类型是const char*,但是比较的时候要转换为unsigned char*,比如:return (*(unsigned char *)first - *(unsigned char *)last);
因为若当前实现中char是signed(char究竟有没有符号是依实现定义的),当*first = 0而*last < 0的时候,应该返回负数表示str1 < str2,所以要强制转换为unsigned char*
7、strstr
char *strstr(const char *s1, const char *s2);
strstr.asm
asm 代码:
先判断str2是否为空,再判断str2是否只有一个字符,如果是,跳转strchr_call
取出str2的第一个字符,循环str1直到找到匹配str2第一个字符,再判断第二个字符是否匹配(str2的第二个字符不可能为0),此时保存遇到第一个字符时的地址,再判断剩余的字符串,不匹配时回到最前的循环,当str2到0时返回此时指向str1的位置,当str1到0时返回0
嗯,没有用kmp算法
字符串函数(2)
0、代码
c++ 代码:
代码:
int main()
{
const char* src = "Hello, world";
char* dest = new char[100];
strlen(src);
strchr(src, ‘l’);
strrchr(src, ‘l’);
strcpy(dest, src);
strcat(dest, src);
_strset(dest, ‘a’);
strpbrk(dest, src);
strcmp(src, dest);
strcoll(src, dest);
strxfrm(dest, src, 10);
strcspn(src, "word");
strspn(dest, src);
strstr("1452345678", "456");
_strrev(dest);
strncmp(src, dest, 10);
strncpy(dest, src, 10);
strncat(dest, src, 10);
_strnset(dest, ‘a’, 10);
return 0;
} size_t strlen(const char *s);
strlen.asm中的定义:
asm 代码:
代码:
strlen proc \
buf:ptr byte
OPTION PROLOGUE:NONE, EPILOGUE:NONE
.FPO ( 0, 1, 0, 0, 0, 0 )
string equ [esp + 4] 按int判断是否下一个4byte中有一个为0(类似memchr的算法)
asm 代码:
代码:
main_loop:
mov eax,dword ptr [ecx] ; read 4 bytes
mov edx,7efefeffh
add edx,eax
xor eax,-1
xor eax,edx
add ecx,4
test eax,81010100h
je short main_loop asm 代码:
代码:
test al, al test ah, ah test eax, 00ff0000h test eax, 0ff000000h
tips:回顾一下memchr的实现,这俩实际是一样的。顺便再参考一下"Hacker’s Delight"的6-1 Find First 0-Byte就ok了
2、strchr & strrchr
char *strchr(const char *s, int c);
char *strrchr(const char *s, int c);
strchr.asm中:
asm 代码:
代码:
strchr proc \
string:ptr byte, \
chr:byte 然后弄一个int里面全是这个需要找的byte,判断找到或是遇到串尾的方法和memchr类似,判断原串中是否有一个byte是0和xor上需要找的byte后是否有0。找到后仍然和memchr一样的判断。
strrchr.asm中:
asm 代码:
代码:
strrchr proc \
uses edi, \
string:ptr byte, \
chr:byte tips:
strrchr中的
add ecx, 1
neg ecx
为什么不写成not ecx?
3、strcpy & strcat & strncpy & strncat
char *strcpy(char * restrict s1,
const char * restrict s2);
char *strncpy(char * restrict s1,
const char * restrict s2,
size_t n);
char *strcat(char * restrict s1,
const char * restrict s2);
char *strncat(char * restrict s1,
const char * restrict s2,
size_t n);
strcat.asm
asm 代码:
代码:
strcpy proc \
dst:ptr byte, \
src:ptr byte asm 代码:
代码:
strcat proc \
dst:ptr byte, \
src:ptr byte strncpy.asm中的strncpy
strncat.asm中的strncat
看了前面那么多实现,这俩已经没有新意了
4、strset
strset.asm
asm 代码:
代码:
_strset proc \
uses edi, \
string:ptr byte, \
val:byte 5、strspn、strcspn、strpbrk
size_t strspn(const char *s1, const char *s2);
size_t strcspn(const char *s1, const char *s2);
char *strpbrk(const char *s1, const char *s2);
这3个实际实现大部分是一样的,就是判断是否找到和返回时略有不同,实现都在:strspn.asm中
预处理语句:
asm 代码:
代码:
ifdef SSTRCSPN
_STRSPN_ equ <strcspn>
elseifdef SSTRPBRK
_STRSPN_ equ <strpbrk>
else ; SSTRCSPN
SSTRSPN equ 1
_STRSPN_ equ <strspn>
endif ; SSTRCSPN asm 代码:
代码:
_STRSPN_ proc \
uses esi, \
string:ptr byte, \
control:ptr byte asm 代码:
代码:
lab listnext ; init char bit map
mov al,[edx]
or al,al
jz short listdone
add edx,1
bts map,eax
jmp short listnext
lab listdone asm 代码:
代码:
lab dstnext
mov al,[esi]
or al,al
jz short dstdone
add esi,1
bt map, eax asm 代码:
代码:
ifdef SSTRSPN
jc short dstnext ; strspn: found char, continue
elseifdef SSTRCSPN
jnc short dstnext ; strcspn: did not find char, continue
elseifdef SSTRPBRK
jnc short dstnext ; strpbrk: did not find char, continue
lea eax,[esi - 1] ; found char, return address of it
endif ; SSTRSPN int strcmp(const char *s1, const char *s2);
int strncmp(const char *s1, const char *s2, size_t n);
int strcoll(const char *s1, const char *s2);
size_t strxfrm(char * restrict s1,
const char * restrict s2,
size_t n);
strcmp.asm
asm 代码:
代码:
strcmp proc \
str1:ptr byte, \
str2:ptr byte dodwords先读入4bytes到eax,然后从al、ah……的顺序一个个比较,不等跳donene,遇到字符串结束跳doneeq
dopartial先判断str1是不是2bytes的倍数,如果是跳doword,否则从edx(是str1)中一次取一个byte来比较
doword每次取2个bytes放在ax中比较
strncmp.c
c++ 代码:
代码:
int __cdecl strncmp (
const char * first,
const char * last,
size_t count
) c++ 代码:
代码:
extern "C" int __cdecl strcoll (
const char *_string1,
const char *_string2
) c++ 代码:
代码:
extern "C" size_t __cdecl strxfrm (
char *_string1,
const char *_string2,
size_t _count
) tips:
1、donene中将eax置为1/-1的方法
asm 代码:
代码:
sbb eax,eax
sal eax,1
add eax,1 2、在c语言实现中(比如strncmp.c),虽然参数类型是const char*,但是比较的时候要转换为unsigned char*,比如:return (*(unsigned char *)first - *(unsigned char *)last);
因为若当前实现中char是signed(char究竟有没有符号是依实现定义的),当*first = 0而*last < 0的时候,应该返回负数表示str1 < str2,所以要强制转换为unsigned char*
7、strstr
char *strstr(const char *s1, const char *s2);
strstr.asm
asm 代码:
代码:
strstr proc \
str1:ptr byte, \
str2:ptr byte 取出str2的第一个字符,循环str1直到找到匹配str2第一个字符,再判断第二个字符是否匹配(str2的第二个字符不可能为0),此时保存遇到第一个字符时的地址,再判断剩余的字符串,不匹配时回到最前的循环,当str2到0时返回此时指向str1的位置,当str1到0时返回0
嗯,没有用kmp算法
评论总数 2
评论
| | 模拟标准函数strcpy,设计如下的复制字符串的函数: char *STRCPY(char *s1, const char *s2); 它将字符串s2复制到s1所指向的字符串空间中,函数的返回值就是s1。 [email]hb8991000@yahoo.com.cn[/email] |
| 发表于 2008-01-22 08:10 PM 作者: hbhg006 |
发表评论 |
作者为 tomato 的最新文章
- C++对象模型(二) (2006-09-23)
- C++对象模型(一) (2006-09-20)
- CRT源码解析(三)字符串函数(2) (2006-05-22)
- CRT源码解析(二)字符串函数(1) (2006-05-07)
- CRT源码解析(一) (2006-05-05)




