如下操作實在類中定義的:
TCHAR m_illegal_chars[13];
TCHAR temp[13] = {_T('|'),
_T('*'),
_T('\\'),
_T(':'),
_T(';'),
_T('>'),
_T('<'),
_T('?'),
_T('"'),
_T(','),
_T('='),
_T('`') };
int i = sizeof(temp)/sizeof(temp[0]); 此時i= 13
_tcscpy_s(m_illegal_chars, i,temp);
上面沒有問題。
但下面的代碼
_tcscpy_s(m_illegal_chars,12,temp); 用12替換i
程序出現異常,down掉了,而且查看了m_illegal_chars為 0*\:;><?",=` 而不是|*\:;><?",=` 第一個字符沒有拷貝成功;
解釋:
類裡面用_tcscpy_s要注意的小細節
復制字符串總是在後2到3個字節後開始,前幾個字節不變,剛開始以為是UTF8頭(EF BB BF)的問題,但那幾個字節不是,文件也不是UTF8的,單步步進一看,errno_t __cdecl _FUNC_NAME(_CHAR *_DEST, size_t _SIZE, const _CHAR*_SRC)
這個函數的 _DEST還真的往前移了幾個字節,ALT+8看匯編,才發現這個地址是this+偏移過來的,但偏移是4字節對齊,這個偏移前面有個bool型變量,導致偏移差了3個字節,vs2010自己還是4字節對齊,導致多加了3個。
字節對齊在結構體或類中。
影響字節對齊有幾個因素。
1) 編譯器對齊字節值。 一般默認為4,可以通過#pragra 更改
2) 類成員對齊字節值。 成員所占的字節
3) 類自己的對齊字節值。 類裡面的最大成員的對齊值。 它將決定類在補齊字節時的值。
4) 類成員有效對齊值。 類成員對齊字節值和編譯器對齊字節值中小的哪個。 它決定類成員占多大字節。
你應該看到了Assert窗口了
"Buffer is too small"
那原因是什麼呢? 字符串str中有8個字符,加上字符串結束符'\0',應該要大小為9的buffer,這裡才會出錯,
至於要求使用strcpy_s,就是考慮到strcpy_s這一系列的函數,可以保證不做越界操作。
非常重要的一個問題:
win32平台上字符串的常見處理方式
1:強烈推薦使用UNICODE來編寫程序。
1,使用unicode,可以使用一個exe,或者DLL來支持多國語言,方便實現本地化。
2,使用Unicode,可以節省WIN32API調用的時間和空間開銷,下面會詳細介紹。
3,可以更好地和COM組件交互,因為COM組件只支持UNICODE。
4,可以更好地和NETFRAMEWORK交互。
對於win32 API函數來說,目前的windows操作系統內部都使用UNICODE來實現和字符串有關的函數。但是通常,都提供ASCLL和Unicode兩個版本的,如CreateWindowA,CreateWindowW,其實內部只有後者的真正實現,前者則是分配內存,轉換傳入的ASCLL字串為寬字符,然後傳入後者,等待後者返回後,釋放內存,並返回。在頭文件中呢,微軟定義了宏
#ifdef UNICODE
#define CreateWindow CreateWindowW
#else
#define CreateWindow CreateWindowA
#endif
,正是通過是否定義了UNICODE來決定調用哪一個。
那麼,C標准庫呢?C標准庫中的字符串處理函數,則不像win32 API一樣,只有寬字符版本的實現,C標准庫有兩個實現,一個實現是ANSI的,一個是UNICODE的,程序員可以在編譯的時候來指定。這一點可以參看深入淺出MFC第一章。比如strlen是針對ASCLL的,wcslen是針對UNICODE的,標准庫如何判斷到底使用哪一個呢?標准庫定義了宏:
#ifdef _UNICODE
#define _tcslen wcslen
#else
#define _tcslen strlen
#endif
可以看出來,標准庫會將UNICODE的標識定義為包含下劃線的形式,而微軟的開發團隊沒有那樣做,微軟的是不帶下劃線的。不過,我們的程序一般來說,既要用到API,又要用到標准庫函數,所以就有了一條規則,要麼UNICODE和_UNICODE都指定,否則都不指定。
下面來總結一下一些原則吧:)
1,建議使用UNICODE。
2,建議不要使用char, wchar_t,而使用CHAR,WCHAR,最好包含tchar.h,使用TCHAR
3,計算字符數組長度時,使用sizeof(ArrayName)/sizeof(ArrayName[0])來計算。
4,同時定義UNICODE和_UNICODE,或者兩個都不要定義。
5,使用windows API函數MultiByteToWideChar和WideCharToMultiByte函數來實現ACSLL字符和UNICODE字符的相互轉換。
6,也可以使用C標准庫中的wcstombs來執行轉換。