C++中的数据类型转换方法总结

来源:互联网 发布:环境监测数据造假 处罚 编辑:程序博客网 时间:2024/05/19 14:16

摘要:本文总结了C/C++中的多种数据类型转换方法,并比较了各自的优劣。给出了推荐的使用建议

int到char*,或者反过来从char*到int,在C/C++中到底有多少种转换方法呢?符合标准的大概有四种。即C数据转换函数族、sprintf/snprintf/sscanf函数族、字符串流std::stringstream、std::strsteam。不符合标准却又广为使用的包括CString和boost::lexical_cast。本文只讨论符合标准的转换方法,其中std::strstream由于已经被C++标准委员为指定为不推荐使用的(deprecated),所以不予考虑了。下面重点讨论三种标准转换方法之间的优劣。源代码的地址是:http://download.csdn.net/source/631475

1.     Int和char*或std::string之间的转换

C数据转换函数族

C数据转换函数族即包括itoa、atoi等数据类型转换函数在内的一大批C函数,在C语言时代曾经被大量使用。源代码如下:

 int i = 10;

 char szBuf[10] = "";

 

 itoa(i, szBuf, 10);

 cout<<"itoa: szBuf = "<<szBuf<<endl;

 i = 0;

 i = atoi(szBuf);

 cout<<"atoi: i = "<<i<<endl;

使用还是比较简单的。一个最大的问题是:没有进行char*的越界检查,可能会造成数组溢出。

snprintf/sscanf

sprintf是用来格式化字符串的一个C函数,sscanf则是从字符串中读取值的一个C函数。由于Herb Sutter(Exceptional C++系列著作的作者)教导我们“永远也不要使用sprintf”,所以这里我们只使用snprintf。由于snprintf进入C标准较晚,所以在你的编译器中也许只能使用非标准的_snprintf(例如我的VC6平台)。源代码如下:

 int i =20;

 char szBuf[10] = "";

 memset(szBuf, 0, sizeof(szBuf));

 _snprintf(szBuf, sizeof(szBuf), "%d", i);

 cout<<"_snprintf: szBuf = "<<szBuf<<endl;

 i = 0;

 sscanf(szBuf,"%d",&i);

 cout<<"sscanf: i = "<<i<<endl;

使用很简单,而且,似乎没有什么内存泄露或者数组越界。

std::stringstream

对流很熟悉的人可能会更快适应std::stringstream的解决方案:

 #include <sstream>

using namespace std;

inti = 30;

string strRel;

 ostringstream oss;

 oss<<i;

 strRel = oss.str();

 cout<<"ostringstream: strRel = "<<strRel<<endl;

 i = 0;

 istringstream iss(strRel);

 iss>>i;

 cout<<"istringstream: i = "<<i<<endl;

使用较为复杂,而且,还使用了两个临时变量oss和iss,这必然带来性能上的开销。

2.     double和char*或std::string之间的转换

C数据转换函数族

当开始进行double和char*之间的转换时,C数据转换函数的缺点暴露无疑。先看源代码:

 double d = 3.1415926;

 char szBuf[18] = "";

 _gcvt(d, 9, szBuf);

 cout<<"_gcvt: szBuf = "<<szBuf<<endl;

 d = 0;

 char* stopstring;

 d = strtod(szBuf, &stopstring);

 cout<<"strtod: d = "<<d<<endl;

首先转换函数的名字就让人大吃一惊,与itoa对应的不是我们想象的dtoa,而是_gcvt,而与atoi对应的是strtod。其次它们的参数很奇怪,没有msdn是不可能明白的。其次,数组越界依然存在。至此我想我们可以抛弃这组函数了。当然,更加无奈的理由在后面。

snprintf/sscanf

snprintf/sscanf表现不错,源代码如下:

 double d = 3.1415926;

 char szBuf[18] = "";

 memset(szBuf, 0, sizeof(szBuf));

 _snprintf(szBuf, sizeof(szBuf), "%f", d);

 cout<<"sprintf: szBuf = "<<szBuf<<endl;

 sscanf(szBuf, "%f", &d);

 cout<<"sscanf: d = "<<d<<endl;

很好,很强大!

std::stringstream

std::stringstream的代码似乎没有任何改动,除了一个int类型改成了double类型:

 double d = 9.1415926;

  string strRel;

 ostringstream oss;

 oss<<d;

 strRel = oss.str();

 cout<<"ostringstream: strRel = "<<strRel<<endl;

 d = 0;

 istringstream iss(strRel);

 iss>>d;

 cout<<"istringstream: d = "<<d<<endl;

写到这里,我似乎看到模板函数在向我招手。

3.     复杂的转换

考虑一个经典的场景,从一个int,一个double和一个string中读出值,然后拼凑为一个输出的字符串。最后,从这个字符串中再将这几个值读出来。

C数据转换函数族

直接看代码:

 int iAge = 25;

 float fPayment = 3.25;

 string strName ="Wang";

 char szBuf[100] = "";

 char szTemp[100];

 strcpy(szBuf,"Age= ");

 itoa(iAge, szTemp, 10);

 strcat(szBuf, szTemp);

 strcat(szBuf," ,Payment= ");

   _gcvt(fPayment, 4, szTemp);

 strcat(szBuf,szTemp);

 strcat(szBuf," ,Name= ");

 strcat(szBuf, strName.c_str());

 cout<<"szBuf = "<<szBuf<<endl;

以上代码的表现真是惨不忍睹,费了几鼻子的劲好歹是转为目标字符串了。转换回来的代码也没有写。也许有,不过那个复杂程度,我看还是算了。而且,strcpy、strcat和几个转换函数都是危险的API,不检查越界的。

snprintf/sscanf

主要看看sscanf的表现:

 int iAge = 25;

 float fPayment = 3.25;

 string strName ="Wang";

 char szBuf[100] = "";

 memset(szBuf, 0, sizeof(szBuf));

 _snprintf(szBuf, sizeof(szBuf), "Age = %d, Payment = %f, ,iAge,fPayment,strName.c_str());

 cout<<"sprintf: szBuf = "<<szBuf<<endl;

 iAge = 0;

 fPayment = 0.0;

 memset(szTemp, 0, sizeof(szTemp));

 sscanf(szBuf,"Age = %d, Payment = %f, ,&iAge,&fPayment,&szTemp);

 strName = szTemp;

 cout<<"sscanf: Age = "<<iAge<<",Payment="<<fPayment<<",name="<<strName<<endl;

snprintf表现还是一如既往的强大。sscanf的表现简直就是perfect,但是要注意,sscanf的样式字符串一定要和snprintf中的样式字符串一模一样,否则其后果是不可预计的。例如,我稍微改动了几个字符,最后的strname就读取错误了。

std::stringstream

std::stringstream的代码很长很长:

 int iAge = 25;

 float fPayment = 3.25;

 string strName ="Wang";


原创粉丝点击