在平常的编程过程中,总免不了格式化字符串。而作为C++程序员,是快乐的也是痛苦不的。快乐是因为我们有多种方式来达到目的,痛苦也是因为有多种方式而难以决策,总是在思索效率与优雅!C++逐步“沦落”的原因也正是因为她的高贵的气质(难以驾驭),时尚的发型(模板),狂野的性格(内存)。哎,迷恋它,她就是我的传说!
先给出一张表格,然后再来一一琢磨!
sprintf | snprintf | stringstream | strsteram | tr2::lexical_cast | boost::format | 备注 | |
易用性 | Y | Y | N | N | Y | N | |
无需额外内存 | Y | Y | N | Y | N | N | |
缓冲区安全 | N | Y | Y | Y | Y | Y | |
类型安全 | N | N | Y | Y | Y | Y | |
是否可用于模板 | N | N | Y | Y | Y | Y | |
效率 | 耗时取样,以sprintf为基准 |
一、sprintf
先来看个成功案例
void FormatString(int i, char *pBuf)
{
sprintf(pBuf, "%4d", i);
}
char buf[5] = {0};
FormatString(10, buf);
cout << buf << endl;
输出: 10
sprintf的易用性是无需多言的,任何学过C语言的童鞋都能搞定,而且不需要额外的内存空间(除开我们制定的Buffer区)。但是,也正是因为他来自C,所以就有一些不良嗜好:
1) 缓冲区溢出:
void FormatString(int i, char *pBuf)
{
sprintf(pBuf, "%4d", i);
}
char buf[3] = {0}; // 这里所指定的缓冲区不能满足%4d的空间
FormatString(10, buf);
cout << buf << endl;
2)类型安全
void FormatString(int i, char *pBuf)
{
sprintf(pBuf, "%4c", i); // 注意,这里是%4c
}
char buf[5] = {0};
FormatString(10, buf);
cout << buf << endl; // 现在什么也不输出
template<typename T>
void FormatString(T value, char *pBuf); // 主模板进行声明,不定义
template<>
void FormatString<int>(int value, char *pBuf) // 特化
{
sprintf(pBuf, "%d", value);
}
template<>
void FormatString<char>(char value, char *pBuf) // 特化
{
sprintf(pBuf, "%c", value);
}
template<>
void FormatString<char *>(char *value, char *pBuf) // 特化
{
sprintf(pBuf, "%s", value);
}
void FormatString(int i, char *pBuf, int nBufLen)
{
_snprintf(pBuf, nBufLen, "%4d", i); // MS用的带下划线的_snprintf
}
char buf[5] = {0};
FormatString(10, buf, sizeof(buf) / sizeof(buf[0]));
cout << buf << endl;
void FormatString(int i, string &str)
{
stringstream temp;
temp << setw(4) << i;
str = temp.str();
}
string str;
FormatString(10, str);
cout << str << endl;
template<typename T>
void FormatString(T value, string &str)
{
stringstream temp;
temp << setw(4) << value; // 现在可以接受任意类型的数据
str = temp.str();
}
template<typename T>
void FormatString(T value, char *pBuf, int nBufLen)
{
strstream temp(pBuf, nBufLen); // 传递指定缓冲区及其大小
temp << setw(4) << value << ends;
}
cout << boost::lexical_cast(10) << endl;
cout << format("%1% %2%") % 36 % 77 << endl; // 输出 36 77
DWORD dwLast = 0;
volatile DWORD count = 1000000;
char buf[64] = {0};
{
CCYPerformance test(dwLast);
for(DWORD i = 0; i != count; ++i)
{
FormatString(0xFFFF, buf);
}
}
cout << "sprintf:" << dwLast << endl;
dwLast = 0;
{
CCYPerformance test(dwLast);
for(DWORD i = 0; i != count; ++i)
{
FormatNString(0xFFFF, buf, 64);
}
}
cout << "snprintf:" << dwLast << endl;
dwLast = 0;
string str;
{
CCYPerformance test(dwLast);
for(DWORD i = 0; i != count; ++i)
{
FormatString(0xFFFF, str);
}
}
cout << "stringstream:" << dwLast << endl;
dwLast = 0;
{
CCYPerformance test(dwLast);
for(DWORD i = 0; i != count; ++i)
{
FormatString(0xFFFF, buf, 64);
}
}
cout << "strstream:" << dwLast << endl;
dwLast = 0;
{
CCYPerformance test(dwLast);
for(DWORD i = 0; i != count; ++i)
{
FormatBoostString(0xFFFF, str);
}
}
cout << "boost::lexical_cast:" << dwLast << endl;
很出乎我得意料~Boost这么快啊~佩服佩服!不愧是大师的佳作!
总结:
默认情况下,效率不是关键 | 如果效率是瓶颈 | |
如果只想做字符转换 | boost::lexical_cast | boost::lexical_cast/snprintf |
简单的格式化(UNICODE/ASCII) | stringstream/strstream | snprintf |
较为负载的格式化 | stringstream/snprintf | snprintf |