字符串和十六进制数的转换(总结网上的代码)
因为用到的转换功能都需要在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++ 标准并没有要求一定要解决类似的不确定问题,所以无论编译器是怎样处理的,解决或者没有解决,应该都是符合标准的。
至此,问题成功解决。