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下也輸出錯誤。