摘要:本文总结了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.youkuaiyun.com/source/631475
1. Int和char*或std::string之间的转换
C数据转换函数族
C数据转换函数族即包括itoa、atoi等数据类型转换函数在内的一大批C函数,在C语言时代曾经被大量使用。源代码如下:
使用还是比较简单的。一个最大的问题是:没有进行char*的越界检查,可能会造成数组溢出。
snprintf/sscanf
sprintf是用来格式化字符串的一个C函数,sscanf则是从字符串中读取值的一个C函数。由于Herb Sutter(Exceptional C++系列著作的作者)教导我们“永远也不要使用sprintf”,所以这里我们只使用snprintf。由于snprintf进入C标准较晚,所以在你的编译器中也许只能使用非标准的_snprintf(例如我的VC6平台)。源代码如下:
使用很简单,而且,似乎没有什么内存泄露或者数组越界。
std::stringstream
对流很熟悉的人可能会更快适应std::stringstream的解决方案:
using namespace std;
inti = 30;
string strRel;
使用较为复杂,而且,还使用了两个临时变量oss和iss,这必然带来性能上的开销。
2. double和char*或std::string之间的转换
C数据转换函数族
当开始进行double和char*之间的转换时,C数据转换函数的缺点暴露无疑。先看源代码:
首先转换函数的名字就让人大吃一惊,与itoa对应的不是我们想象的dtoa,而是_gcvt,而与atoi对应的是strtod。其次它们的参数很奇怪,没有msdn是不可能明白的。其次,数组越界依然存在。至此我想我们可以抛弃这组函数了。当然,更加无奈的理由在后面。
snprintf/sscanf
snprintf/sscanf表现不错,源代码如下:
很好,很强大!
std::stringstream
std::stringstream的代码似乎没有任何改动,除了一个int类型改成了double类型:
写到这里,我似乎看到模板函数在向我招手。
3. 复杂的转换
考虑一个经典的场景,从一个int,一个double和一个string中读出值,然后拼凑为一个输出的字符串。最后,从这个字符串中再将这几个值读出来。
C数据转换函数族
直接看代码:
以上代码的表现真是惨不忍睹,费了几鼻子的劲好歹是转为目标字符串了。转换回来的代码也没有写。也许有,不过那个复杂程度,我看还是算了。而且,strcpy、strcat和几个转换函数都是危险的API,不检查越界的。
snprintf/sscanf
主要看看sscanf的表现:
snprintf表现还是一如既往的强大。sscanf的表现简直就是perfect,但是要注意,sscanf的样式字符串一定要和snprintf中的样式字符串一模一样,否则其后果是不可预计的。例如,我稍微改动了几个字符,最后的strname就读取错误了。
std::stringstream
std::stringstream的代码很长很长: