VC之那些 strcpy 往事

 

首先让我们看看VC6.0里面库函数   strcpy源码:

1 char * __cdecl strcpy(char * dst, const char * src)
2 {
3 char * cp = dst;
4
5 while( *cp++ = *src++ )
6 ; /* Copy src over dst */
7
8 return( dst );
9 }

可以看到代码简单,第一个没有考虑目的字符串与源字符串的大小比较,他就是只管拷贝,不管指针是否越界。

 

那么我们先测试一小段程序:

#include <stdio.h>

int _tmain(int argc, _TCHAR* argv[])
{

char strb[]="999456789";
char stra[]="123";

strcpy(stra,strb);

printf("stra=%s\nstrb=%s\n",stra,strb);

}

这个测试程序在VC6.0环境 运行结果是 stra=999456789     strb=56789

                      在VC9.0环境运行结果是 stra=999456789      strb=999456789   同时越界报错

好了 我们的问题来了,为什么结果不一样,其实VC6.0内存分配策略很傻比,就是 123\0999456789  那么strcpy之后呢?

变成 999456789\0789   因而stra变成999456789,而strb指针未变仍指向第五位,所以输出56789遇\0结束。

VC9.0内存分配策略聪明的多,他是如何解决呢,他是在strcpy的时候分给stra和strb同样大小的内存,但是stra越界要报错

所以strcpy之前是 123\0######   999456789\0 而后strcpy的结果是999456789\0  999456789\0 这样两个字符数组被输出出来

但是有越界访问报错。

上面的猜测究竟对不对呢,我们在做个实验。我们知道VC9.0里面实现strcpy类都是采用汇编实现的,那好我们也采用汇编实现吧。

我们的目的就是为了模仿VC9.0的库函数strcpy

 1 char *StrcpyUnSafe(char* dstr,const char* sstr)
2 {
3 __asm
4 {
5 mov edi,dstr;
6 mov esi,sstr;
7 N:
8 mov dl,[esi];
9 cmp dl,'\0';
10 jz over;
11 mov [edi],dl;
12 inc edi;
13 inc esi;
14 jmp N;
15 over:
16 }
17 return dstr;
18 }
19
20
21 int _tmain(int argc, _TCHAR* argv[])
22 {
23
24 char strb[]="999456789";
25 char stra[]="123";
26
27
28 StrcpyUnSafe(stra,strb);
29 printf("stra=%s\nstrb=%s\n",stra,strb);
30 return 0;
31 }

将这个程序运行,我们查看结果:

stra=999456789烫?99456789
strb=999456789
请按任意键继续. . .

可以看到stra里面存放的内容 因为我们没有添加\0结束符,所以会出现越界访问到strb的内容,对,就是strb的内容,这里可以清晰表明,9.0对内存分配策略,或者只接用指针将str+3的内容变为2 可以看到内存分配结果:

1232烫烫烫烫999456789请按任意键继续. . ..

所以9.0显然提高了智商,预留隔开了一些字节但是如果strb太大 仍然会覆盖strb的一些内容。

猜想属实,再次向各位大牛问声。如果你们有9.0库函数源码请发送我邮箱

好了 上述猜想得以验证,下面俺想吧自己实现的两个strcpy粘贴下,都是自己写的,一个是安全copy一个是非安全copy,安全copy就是只能复制目的字符串所能承载的大小字符。非安全就无所谓了 但是会报错,好了,上代码吧。

 1 #include "stdafx.h"
2 #include <stdio.h>
3 //#include <string>
4
5 char *StrcpySafe(char* dstr,const char* sstr)
6 {
7 __asm
8 {
9 mov edi,dstr;
10 mov esi,sstr;
11 N:
12 mov dl,[esi];
13 cmp dl,'\0';
14 jz over;
15 mov al,[edi];
16 cmp al,'\0';
17 jz over;
18 mov [edi],dl;
19 inc edi;
20 inc esi;
21 jmp N;
22 over:
23 }
24 return dstr;
25 }
26
27
28 char *StrcpyUnSafe(char* dstr,const char* sstr)
29 {
30 __asm
31 {
32 mov edi,dstr;
33 mov esi,sstr;
34 N:
35 mov dl,[esi];
36 cmp dl,'\0';
37 jz over;
38 mov [edi],dl;
39 inc edi;
40 inc esi;
41 jmp N;
42 over:
43 mov [edi],'\0'
44 }
45 return dstr;
46 }
47
48
49 int _tmain(int argc, _TCHAR* argv[])
50 {
51
52 char strb[]="999456789";
53 char stra[]="123";
54 char *pstr=stra;
55 *(pstr+3)='2';
56 printf("%s\n",pstr);
57 char strB[]="999456789";
58 char strA[]="123";
59
60
61
62 StrcpySafe(strA,strB);
63 printf("strA=%s\nstrB=%s\n",strA,strB);
64 StrcpyUnSafe(stra,strb);
65 printf("stra=%s\nstrb=%s\n",stra,strb);
66 return 0;
67 }

 

初次写文章难免存在很多失误,如果我是迷糊在什么地方 请告知我。谢谢!

 

posted on 2012-03-01 18:57  北冥茶花开  阅读(370)  评论(0编辑  收藏  举报

导航