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