千家信息网

C++怎么生成格式化的标准字符串

发表于:2024-11-26 作者:千家信息网编辑
千家信息网最后更新 2024年11月26日,本篇内容主要讲解"C++怎么生成格式化的标准字符串",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"C++怎么生成格式化的标准字符串"吧!两种格式化字符串方法
千家信息网最后更新 2024年11月26日C++怎么生成格式化的标准字符串

本篇内容主要讲解"C++怎么生成格式化的标准字符串",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"C++怎么生成格式化的标准字符串"吧!

两种格式化字符串方法

众所周知,C++的std::string功能残缺,各种功能都没有,比如格式化字符串功能。

在python3中,支持两种格式化字符串的方法,一种是C风格,格式化的部分用%开头,%后面的对应具体类型(比如%s对应字符串%d对应整型),另一种则是类型无关的风格,{0}对应第1个参数,{1}对应第2个参数。

>>> "{0}'s age is {1}".format("赤红", 11)"赤红's age is 11">>> "%s's age is %d" % ("赤红", 11)"赤红's age is 11"

而在C++中则只能借用C函数,用snprintf来格式化一片缓冲区

#define BUFFSIZE 512 char buf[BUFFSIZE]; snprintf(buf, BUFFSIZE, "%s's age is %d\n", "赤红", 11);

亦或者用类型无关的流运算符

std::ostringstream os; os << "赤红" << "'s age is " << 11 << "\n"; std::string s = os.str();

暂且不谈效率问题,这种用<<拼接多个不同类型对象的做法代码量较大,而且在控制具体输出格式时更为麻烦,比如控制数字所占位数,或者小数点后位数。至少繁杂得让我总是记不起来,宁可使用C风格snprintf来控制。比如

double d = 3.1415926; snprintf(buf, BUFFSIZE, "圆周率: %-8.3lf是祖冲之发现的\n", d);

$ ./a.out 圆周率: 3.142 是祖冲之发现的

通过%-8.3lf将lf(long float即double)类型的浮点数设置占位数为8,设置小数点后位数为3,负号表示左对齐,这种表示方法非常简单紧凑。

至于用C++的iomanip头文件实现,我还花了点时间查文档。

double d = 3.1415926; os << "圆周率: " << std::setw(8) << std::fixed << std::setprecision(3) << std::left << d << "是祖冲之发现的\n";

除了代码如此之长以及有可能漏掉std::fixed外,还有问题在于setprecision已经改变了默认设置,也就是说,如果再os <<传入一个浮点数,保留的小数点位数仍然是3位。

也许有人说,这种好处在于setprecision和setw接收的可以是一个变量而非常量。实际上snprintf一样可以做到。

double d = 3.1415926; int n1 = 8, n2 = 3; snprintf(buf, BUFFSIZE, "圆周率: %-*.*lf是祖冲之发现的\n", n1, n2, d);

C++包装snprintf生成格式化的std::string对象

在APUE UNP TLPI这几本讲Linux下C编程的书中,都自己写了错误处理库来包装snprintf产生格式化的输出,以免每次重复定义缓冲区/调用snprintf等等。

这样的做法有个缺陷就是缓冲区(字符数组)长度有限制,当然一般而言buffer size定义得足够大的话是足够的,毕竟打印太长的格式化字符串不如多调用几次函数。

另一方面,由于这些函数仅仅是打印信息,尤其是经常打印信息后直接退出程序。所以不会返回错误字符串。如果在C++中想要把错误信息作为异常传给上一层处理,这些函数是不够的。因此需要简单修改下。

inline std::string format_string(const char* format, va_list args) { constexpr size_t oldlen = BUFSIZ; char buffer[oldlen]; // 默认栈上的缓冲区 va_list argscopy; va_copy(argscopy, args); size_t newlen = vsnprintf(&buffer[0], oldlen, format, args) + 1; newlen++; // 算上终止符'' if (newlen > oldlen) { // 默认缓冲区不够大,从堆上分配 std::vector newbuffer(newlen); vsnprintf(newbuffer.data(), newlen, format, argscopy); return newbuffer.data(); } return buffer;}inline std::string format_string(const char* format, ...) { va_list args; va_start(args, format); auto s = format_string(format, args); va_end(args); return s;}

这是模仿UNP的实现,定义形参为va_list和...的两个版本,其中接受va_list的版本还可为其它函数所用。因为C风格的可变参数列表...不能作为参数传递。另一点,va_list类型也不一定有拷贝构造函数,因此得用va_copy来拷贝一份va_list,以供第二次使用。

C++11新增了可变模板参数特性,使得上述代码可以得到简化

template inline std::string format_string(const char* format, Args... args) { constexpr size_t oldlen = BUFSIZ; char buffer[oldlen]; // 默认栈上的缓冲区 size_t newlen = snprintf(&buffer[0], oldlen, format, args...); newlen++; // 算上终止符'' if (newlen > oldlen) { // 默认缓冲区不够大,从堆上分配 std::vector newbuffer(newlen); snprintf(newbuffer.data(), newlen, format, args...); return std::string(newbuffer.data()); } return buffer;}

而传递可变模板参数也变得十分容易(使用forward完美转发),示例代码如下

xyz@ubuntu:~/unp_practice/lib$ cat test.cc #include #include #include "format_string.h"template void errExit(const char* format, Args... args) { auto errmsg = format_string(format, std::forward(args)...); errmsg = errmsg + ": " + strerror(errno) + "\n"; fputs(errmsg.c_str(), stderr); exit(1);}int main() { const char* s = "hello world!"; int fd = -1; if (write(fd, s, strlen(s)) == -1) errExit("write \"%s\" to file descriptor(%d) failed", s, fd); return 0;}xyz@ubuntu:~/unp_practice/lib$ g++ test.cc -std=c++11xyz@ubuntu:~/unp_practice/lib$ ./a.out write "hello world!" to file descriptor(-1) failed: Bad file descriptor

到此,相信大家对"C++怎么生成格式化的标准字符串"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

格式 字符 字符串 C++ 缓冲区 缓冲 函数 参数 类型 生成 代码 圆周 圆周率 方法 风格 祖冲之 标准 不够 位数 信息 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 中国邮储软件开发招聘 网络安全绘画作品小学生 数据库系统原理课后答案沈钧毅 华为服务器如何设置两个raid 成都应用软件开发价位 湖南拓思软件开发公司 公安部发布关于网络安全的文章 服务器风扇和普通风扇的区别 服务器挂机赚钱日赚50 安卓3d门窗类软件开发 湖南汇的网络技术 防范网络安全问题教案幼儿园 latex 刷新数据库 服务器管理工具 推荐 宝信软件软件开发待遇 微光股份数据库 贵人网络技术有限公司 网络安全周心得体会300字作文 暗黑3装备数据库 网络安全和信息化局是干什么的 华为服务器如何设置两个raid 常见的计算机网络安全措施有 上海聚嘉网络技术有限公司 华为sdn软件开发工程师 微服务集群连接数据库 内网服务器通公网安全吗 学软件开发为什么要学高数 济南地区浪潮服务器代理商哪家好 盗贼之海服务器管理 中国网络技术集团公司
0