strcpy_s用法


转自:strcpy_s与strcpy的比较

2014-07-22 13:54:59

strcpy_s和strcpy()函数的功能几乎是一样的。strcpy函数,就象gets函数一样,它没有方法来保证有效的缓冲区尺寸,所以它只能假定缓冲足够大来容纳要拷贝的字符串。在程序运行时,这将导致不可预料的行为。用strcpy_s就可以避免这些不可预料的行为。
这个函数用两个参数、三个参数都可以,只要可以保证缓冲区大小。
三个参数时:第一个参数为指针

1 errno_t strcpy_s(
2     char *strDestination,
3     size_t numberOfElements,
4     const char *strSource
5 );

两个参数时:第一个参数为数组

1 errno_t strcpy_s(
2     char (&strDestination)[size],
3     const char *strSource
4 ); // C++ only

例子:

 1 #include<iostream>
 2 #include<cstring>
 3 using namespace std;
 4  
 5 void Test(void)
 6 {
 7 char *str1=NULL;
 8 str1=new char[20];
 9 char str[7];
10 strcpy_s(str1,20,"hello world");//三个参数
11 strcpy_s(str,"hello");//两个参数但如果:char *str=new char[7];会出错:提示不支持两个参数
12 cout<<"strlen(str1):"<<strlen(str1)<<endl<<"strlen(str):"<<strlen(str)<<endl;
13 printf(str1);
14 printf("\n");
15 cout<<str<<endl;
16 }
17  
18 int main()
19 {
20 Test();
21 return 0;
22 }

输出为:

1 strlen(str1): 11        //另外要注意:strlen(str1)是计算字符串的长度,  不包括字符串末尾的“\0”!!!
2 strlen(str): 5
3 hello world
4 hello

 

转自:strcpy_s函数的实现
代码是这样的:
 1 _FUNC_PROLOGUE
 2 errno_t __cdecl _FUNC_NAME(_CHAR *_DEST, size_t _SIZE, const _CHAR *_SRC)
 3 {
 4     _CHAR *p;
 5     size_t available;
 6 
 7     /* validation section */
 8     _VALIDATE_STRING(_DEST, _SIZE);
 9     _VALIDATE_POINTER_RESET_STRING(_SRC, _DEST, _SIZE);
10 
11     p = _DEST;
12     available = _SIZE;
13     while ((*p++ = *_SRC++) != 0 && --available > 0)
14     {
15     }
16 
17     if (available == 0)
18     {
19         _RESET_STRING(_DEST, _SIZE);
20         _RETURN_BUFFER_TOO_SMALL(_DEST, _SIZE);      //在这里提示错误,使用_CrtDbgReportW
21     }
22     _FILL_STRING(_DEST, _SIZE, _SIZE - available + 1);
23     _RETURN_NO_ERROR;
24 }

也就是说当源串大于目地串时程序报错,是有点进步意义,但不能防止所有错误,在用字串函数时还得要非常小心。

在debug版下它最终由_CrtDbgReportW报错,在release版下呢?

从调用堆栈上看是先调用_invalid_parameter,然后调用_crt_debugger_hook,显示错误提示框(_crt_debugger_hook可以用自己的代码替换掉)

实际上_RETURN_BUFFER_TOO_SMALL(_DEST, _SIZE)最终调用下面的代码:

 1 #define _VALIDATE_RETURN_VOID( expr, errorcode )                               /
 2     {                                                                          /
 3         int _Expr_val=!!(expr);                                                /
 4         _ASSERT_EXPR( ( _Expr_val ), _CRT_WIDE(#expr) );                       /
 5         if ( !( _Expr_val ) )                                                  /
 6         {                                                                      /
 7             errno = errorcode;                                                 /
 8             _INVALID_PARAMETER(_CRT_WIDE(#expr));                              /
 9             return;                                                            /
10         }                                                                      /
11     }

_ASSERT_EXPR( ( _Expr_val ), _CRT_WIDE(#expr) );这句是在debug下用的,而release版下会调用 _INVALID_PARAMETER(_CRT_WIDE(#expr)); 可惜的是错误提示少了一些。

 

这种debug版与release版不同的处理方式好象已经成为了一个定规,这样真的好吗?像assert在release版下不报错,并不是一个好的方式,我还是比较喜欢重定义assert让它在release下也输出错误。

 

 

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM