Win CE開(kāi)發(fā)特性及忠告
在Intel系列處理器上,你可以在一奇數內存地址儲存任何變量或數組,不會(huì )導致任何致命的錯誤影響。但在H/PC上,這一點(diǎn)不一定能行 ? 你必須對大于一個(gè)字節的數據類(lèi)型小心謹慎,包括定義為無(wú)符號短型(unsigned short) 的wchar_t。當你設法訪(fǎng)問(wèn)它們的時(shí)候,將它們置于奇地址會(huì )導致溢出。
編輯器經(jīng)常在這些問(wèn)題上提醒你。你無(wú)法管理堆棧變量地址,并且編輯器會(huì )檢查確定這些地址與變量類(lèi)型是否相匹配。同樣,運行時(shí)間庫必須保證從堆中分配的內存總是滿(mǎn)足一個(gè)word邊界 ,所以你一般不必擔心那兩點(diǎn)。但是,如果應用程序含有用memcpy()函數拷貝內存區域的代碼,或者使用了某種類(lèi)型的指針算術(shù)以確定內存地址,問(wèn)題也許就出現了??紤]下面的例子:
int send_name (TCHAR * pszName)
{
char *p, *q;
int nLen=(_tcslen(pszName) + 1) * sizeof(TCHAR);
p=maloc(HEADER_SIZE + nLen);
if(p)
{
q = p + HEADER_SIZE;
_tcscpy((TCHAR*)q, pszName);
}
/* etc */
這段代碼是從堆中分配內存并復制一個(gè)字符串,在字符串的開(kāi)頭留一個(gè)HEADER_SIZE的大小。假設UNICODE定義了,那么該字符串就是一個(gè)widechar字符串。如果HEADER_SIZE是一個(gè)偶數,這段代碼就會(huì )正常工作,但如果HEADER_SIZE為奇數,這段代碼就會(huì )出錯,因為q指向的地址也將為奇數。
注意,當你在Intel系列處理器中的Windows CE仿真器上測試這段代碼時(shí),這個(gè)問(wèn)題是不會(huì )發(fā)生的。
在這個(gè)例子中,只要確保HEADER_SIZE為偶數,你就可以避免問(wèn)題的發(fā)生。然而,在某些情況下你也許不能這么做。例如,如果程序是從一臺式PC輸入數據,你也許不得不采用事先定義過(guò)的二進(jìn)制格式,盡管它對H/PC不適合。在這種情況下,你必須采用函數,這些函數用字符指針控制字符串而不是TCHAR指針。如果你知道字符串的長(cháng)度,就可以用memcpy()復制字符串。因此,采用逐個(gè)字節分析Unicode字符串的函數也許足以確定字符串在widechars中的長(cháng)度。
在A(yíng)NSI和Unicode字符串之間進(jìn)行翻譯
如果你的Windows CE應用程序接口于臺式PC,也許你必須操作PC機中的ANSI字符串數據(例如,char字符串)。即使你在程序中只用到Unicode字符串,這都是事實(shí)。
你不能在Windows CE上處理一個(gè)ANSI字符串,因為沒(méi)有操縱它們的庫函數。最好的解決辦法是將ANSI字符串轉換成Unicode字符串用到H/PC上,然后再將Unicode字符串轉換回ANSI字符串用到PC上。為了完成這些轉換,可采用MultiByteToWideChar()和WideCharToMultiByte () Win32 API 函數。
對于Windows CE 1.0的字符串轉換,劈開(kāi)(hack)
在Windows CE 1.0 版本中,這些Win32API函數還沒(méi)有完成。所以如果你想既要支持CE 1.0又能支持CE 2.0,就必須采用其它函數。將ANSI字符串轉換成Unicode字符串可以用wsprintf(),其中第一個(gè)參數采用一widechar字符串,并且認識%S(大寫(xiě)),意思是一個(gè)字符串。由于沒(méi)有wsscanf() 和 wsprintfA(),你必須想別的辦法將Unicode字符串轉換回ANSI字符串。由于Windows CE 1.0不在國家語(yǔ)言支持(NLS)中,你也許得求助于hack,如下所示:
/*
Definition / prototypes of conversion functions
Multi-Byte (ANSI) to WideChar (Unicode)
atow() converts from ANSI to widechar
wtoa() converts from widechar to ANSI
*/
#if ( _WIN32_WCE >= 101)
#define atow(strA, strW, lenW)
MultiByteToWidechar (CP_ACP, 0, strA, -1, strW, lenW)
#define wtoa(strW, strA, lenA)
WideCharToMutiByte (CP_ACP, 0, strW, -1, strA, lenA, NULL, NULL)
#else /* _WIN32_WCE >= 101)*/
/*
MultiByteToWideChar () and WideCharToMultiByte() not supported o-n Windows CE 1.0
*/
int atow(char *strA, wchar_t *strW, int lenW);
int wtoa(wchar_t *strW, char *strA, int lenA);
endif /* _WIN32_WCE >= 101*/
#if (_WIN32_WCE 101)
int atow(char *strA, wchar_t *strW, int lenW)
{
int len;
char *pA;
wchar_t *pW;
/*
Start with len=1, not len=0, as string length returned
must include null terminator, as in MultiByteToWideChar()
*/
for(pA=strA, pW=strW, len=1; lenW; pA++, pW++, lenW--, len++)
{
*pW = (lenW = =1) ? 0 : (wchar_t)( *pA);
if( ! (*pW))
break;
}
return len;
}
int wtoa(wxhar_t *strW, char *strA, int lenA)
{
int len;
char *pA;
wchar_t *pW;
/*
Start with len=1,not len=0, as string length returned
Must include null terminator, as in WideCharToMultiByte()
*/
for(pA=strA, pW=strW, len=1; lenA; pa++, pW++, lenA--, len++)
{
pA = (len==1)? 0 : (char)(pW);
if(!(*pA))
break;
}
return len;
}
#endif /*_WIN32_WCE101*/
這種適合于Windows CE 1.0的實(shí)現辦法比使用wsprintf()函數要容易,因為使用wsprintf()函數更難以限制目標指針所指向的字符串的長(cháng)度。
選擇正確的字符串比較函數
如果你要分類(lèi)Unicode標準字符串,你會(huì )有以下幾個(gè)函數可供選擇:
wcscmp(), wcsncmp(), wcsicmp(), 和wcsnicmp()
wcscoll(), wcsncoll(), wcsicoll(),和wcsnicoll()
CompareString()
第一類(lèi)函數可用來(lái)對字符串進(jìn)行比較,不參考當地(Locale)或外文字符。如果你永遠不想支持外文,或者你僅僅想測試一下兩個(gè)字符串的內容是否相同,這類(lèi)函數非常好用。
第二類(lèi)函數使用現有的當地設置(current locale settings)(系統設置,除非你在字符串比較函數之前調用了wsetlocale()函數)來(lái)比較兩個(gè)字符串。這些函數也能正確分類(lèi)外文字符。如果當地的字符C(C locale)被選定,這些函數與第一類(lèi)函數就具有了相同的功能。
評論