字符串格式化大比拼
来源:互联网 发布:cf辅助源码群 编辑:程序博客网 时间:2024/05/16 19:42
在平常的编程过程中,总免不了格式化字符串。而作为C++程序员,是快乐的也是痛苦不的。快乐是因为我们有多种方式来达到目的,痛苦也是因为有多种方式而难以决策,总是在思索效率与优雅!C++逐步“沦落”的原因也正是因为她的高贵的气质(难以驾驭),时尚的发型(模板),狂野的性格(内存)。哎,迷恋它,她就是我的传说!
先给出一张表格,然后再来一一琢磨!
sprintfsnprintfstringstreamstrsteramtr2::lexical_castboost::format备注易用性YYNNYN 无需额外内存YYNYNN 缓冲区安全NYYYYY 类型安全NNYYYY 是否可用于模板NNYYYY 效率 耗时取样,以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;
完了,内存遭到了破坏,在VS2008下测试,运行时会提示“Run-Time Check Failure #2 - Stack around the variable 'buf' was corrupted.”
2)类型安全
void FormatString(int i, char *pBuf)
{
sprintf(pBuf, "%4c", i); // 注意,这里是%4c
}
char buf[5] = {0};
FormatString(10, buf);
cout << buf << endl; // 现在什么也不输出
由于printf家族都是使用的C可变参数列表,编译期间不检查参数列表(好像有个lint的工具可以检查,没用过。)
3)使用模板来解决类型安全
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);
}
够了,不想再写了!来看其他的替代方案吧!
二、snprintf(M$用的是_snprintf)
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;
正确输出: 10
在C99中snprintf成为了标准的一部分,这样,就能避免程序缓冲区溢出,除非故意把指定缓冲区长度搞错。但是还是不能解决类型安全的为题
三、std::stringstream
看列子
void FormatString(int i, string &str)
{
stringstream temp;
temp << setw(4) << i;
str = temp.str();
}
string str;
FormatString(10, str);
cout << str << endl;
特点很鲜明:易用性不如sprintf,使用了额外的缓冲区stringstream。但是现在没有了缓冲区溢出和类型安全的担心,而且我们可以做个更通用的版本
template<typename T>
void FormatString(T value, string &str)
{
stringstream temp;
temp << setw(4) << value; // 现在可以接受任意类型的数据
str = temp.str();
}
四、std::strstream
哎,这个要被抛弃了,成为标准的牺牲品!还是给他点信心吧
template<typename T>
void FormatString(T value, char *pBuf, int nBufLen)
{
strstream temp(pBuf, nBufLen); // 传递指定缓冲区及其大小
temp << setw(4) << value << ends;
}
不错的表现啊(相对stringstream讲,无需额外的内存),但是要被标准抛弃~
五、str2::lexical_cast / boost::lexical_cast
cout << boost::lexical_cast(10) << endl;
很简单,实现也是基于stringstream的,而其快进入C++标准了,不需多言。
六、boost::format
cout << format("%1% %2%") % 36 % 77 << endl; // 输出 36 77
用法与srpintf类似,不过看上去N不像~不喜欢!
效率比试:
VS2008 Release模式
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_castboost::lexical_cast/snprintf简单的格式化(UNICODE/ASCII)stringstream/strstreamsnprintf较为负载的格式化stringstream/snprintfsnprintf- 字符串格式化大比拼
- 字符串copy效率大比拼~
- 字符串copy效率大比拼
- String.format参加字符串拼接大比拼
- String.format参加字符串拼接大比拼
- Swift入门之字符串联接---语言大比拼
- WEB服务器大比拼
- WEB服务器大比拼
- 搓澡版本大比拼
- 搞笑汉字大比拼
- 配置管理工具大比拼!
- 中外流氓软件大比拼
- 房价大比拼
- 国产语音卡大比拼
- 文字大比拼
- 配置管理工具大比拼
- 加密解密大比拼
- WEB服务器大比拼
- 【转】VBA跳出文件对话框
- 传智播客-递归(1)-jvm中保存运行方法的原理及递归方法设计要点
- 在Fedora 11上安装mysql并实现远程访问
- HTTP 协议分析工具
- GC2
- 字符串格式化大比拼
- Ubuntu下安装SCIM输入法
- C++_Syntax_Convesion
- 推荐一个免费的在线操作系统Ghost。
- java 十大异常
- 做网站与做人
- 开发者网站收藏1
- 利用JQuery制作可编辑的表格
- BeginPaint和GetDC有什么区别?(转)