因為用到的轉換功能都需要在Qt中實現,所以先介紹一下QString 、string和char * 的轉換
1、QString 轉換為 string
1 using namespace std;//添加命名空間 2 3 QString str; 4 string myString = str.toStdString();
2、string 轉換為QString
1 using namespace std; 2 3 string myString; 4 QString myQString = QString::fromStdString(myString);
3、QString 轉換為char *
1 QString myQString; 2 char *p = (char *)myQString.toStdString().c_str();
4、char *轉換為QString
1 char *p; 2 QString myQString = QString(p);
6、字符串和十六進制數轉換
1 //十六進制數組轉為字符串 2 //參數HexData為數組指針 3 //參數iLen為數組長度 4 //返回值為對應的十六進制字符串 5 string HexToStr(const unsigned char* HexData , int iLen);
6 //字符串轉為十六進制數 7 //參數strData為字符串形式的十六進制值 8 //參數HexData為數組指針 9 //參數iLen為數組HexData的長度 10 //返回值為0表示轉換成功,非0則表示轉換失敗 11 //(返回1表示長度不匹配) 12 //(返回2表示字符串中包含非十六進制的字符) 13 int StrToHex(string strData, unsigned char* HexData , int iLen);
1 static const char Num_Hex[16]={'0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , 'A' , 'B' , 'C' , 'D' , 'E' , 'F'}; 2 3 //十六進制數組轉為字符串 4 //參數HexData為數組指針 5 //參數iLen為數組長度 6 //返回值為對應的十六進制字符串 7 string HexToStr(const unsigned char* HexData , int iLen) 8 { 9 string strRet; 10 unsigned char ucTmp; 11 for(int i=0; i<iLen; i++) 12 { 13 ucTmp = *(HexData + i); 14 strRet += Num_Hex[(ucTmp>>4) & 0x0f]; 15 strRet += Num_Hex[ucTmp & 0x0f]; 16 } 17 return strRet; 18 } 19 //字符串轉為十六進制數 20 //參數strData為字符串形式的十六進制值 21 //參數HexData為數組指針 22 //參數iLen為數組HexData的長度 23 //返回值為0表示轉換成功,非0則表示轉換失敗 24 //(返回1表示長度不匹配) 25 //(返回2表示字符串中包含非十六進制的字符) 26 int StrToHex(string strData, unsigned char* HexData , int iLen) 27 { 28 int iRet=0; 29 unsigned char ucTmp; 30 transform(strData.begin(), strData.end(), strData.begin(), ::toupper);//字符串轉為大寫 31 int sz = strData.size(); 32 if(sz != 2*iLen) 33 return 1; 34 for(int i=0 ; i<sz; i++) 35 { 36 ucTmp = strData.at(i); 37 //0-9的ASCII碼為0x30 - 0x39 , A-F的ASCII碼為0x41-0x46 38 if(!((ucTmp>=0x30 && ucTmp<=0x39) || (ucTmp>=0x41 && ucTmp<=0x46))) 39 return 2; 40 } 41 sz = sz/2; 42 for(int i=0 ; i<sz; i++) 43 { 44 ucTmp = strData.at(2*i); 45 if(ucTmp>=0x30 && ucTmp<=0x39) 46 { 47 ucTmp -= 0x30; 48 } 49 else if(ucTmp>=0x41 && ucTmp<=0x46) 50 { 51 ucTmp -= 0x37; 52 } 53 *(HexData+i) = ucTmp<<4; 54 55 ucTmp = strData.at(2*i+1); 56 if(ucTmp>=0x30 && ucTmp<=0x39) 57 { 58 ucTmp -= 0x30; 59 } 60 else if(ucTmp>=0x41 && ucTmp<=0x46) 61 { 62 ucTmp -= 0x37; 63 } 64 *(HexData+i) += ucTmp; 65 } 66 return iRet; 67 }
1 transform(strData.begin(), strData.end(), strData.begin(), ::toupper);//字符串轉為大寫
代碼說明:為什么要加 ::toupper
在<cctype>里面聲明了一個C版本的函數tolower,int tolower(int); 而在<local>中間也聲明了一個函數模板:
template <class charT> charT tolower( charT c , const locale& loc );
如果這兩個頭文件都同時包含到程序中來的話(C++標准頭文件可能會包含另外的標 准頭文件。例如有的編譯器在一些標准頭文件中,如<iostream>,會包含<locale>或<cctype> 頭文件。這樣,包含<iostream>可能會引入<locale>或<cctype>),由於這些 tolower 函數都位於同一 std 名字空間,於是形成了函數重載。這樣的話,transform 函數(也是一個模板函數)的第四個參數是tolower 的時候,此時給定的 tolower 只是作為一個函數指針使用,缺乏類型推導所需要的函數參數信息,所以無法推導出函數的類型,也就無法決定使用哪一個重載函數。
如果想使用非模版的 tolower 函數,有多種方法可以解決:
transform( s.begin(), s.end(), s.begin(), (int(*)(int))tolower);
或者:
int (*pf)( int ) = tolower; // pf 是一個函數指針,其類型已經明確。 transform( s.begin(), s.end(), s.begin(), pf );
或者:
// 使用一個包裝函數,避免直接使用 tolower 函數由於重載帶來的問題。 int my_tolower( int c ) { return tolower( c ); // 根據 c 的類型可以確定使用 tolower 的哪個重載函數。 }
// …
// my_tolower 是非模版非重載函數,避免了函數重載帶來的類型解析問題。
transform( s.begin(), s.end(), s.begin(), my_tolower );
另外,非模板函數的 tolower 其實是來自於標准 C 庫函數,因此在 C++ 標准庫中它同時位於全局和 std 名字空間。既然 std 名字空間內 tolower 函數有可能形成函數重載,但是在全局名字空間中的 tolower 函數卻只有一個,所以也可以直接使用全局名字空間中的 tolower:
transform( s.begin(), s.end(), s.begin(), ::tolower);
當然,模板函數和非模板函數 tolower 的區別還是很明顯的:前者有兩個參數,后者只有一個參數。而程序中使用的 transform 函數的第四個參數要求,如果是函數的話只能是有一個參數的函數,所以從這方面來說重載函數的選擇問題是可以得到解決的。有的編譯器可能就是根據這一點做了 進一步的判別處理,或者直接選擇了非模版函數,從而解決了這一問題。但是 C++ 標准並沒有要求一定要解決類似的不確定問題,所以無論編譯器是怎樣處理的,解決或者沒有解決,應該都是符合標准的。
至此,問題成功解決。