C++snprintf和stringstream,一篇就够啦!

文章目录

    • 前言
    • snprintf()
    • sstream
      • str()的使用
      • clear()的使用
    • 对于stringstream的疑惑

前言

最近写了一个Github的C++Json解析器,这是其中遇到的一个问题,在查询大量资料之后编写了这篇文章。

snprintf()

这个函数位于头文件cstdio中,我们先来看看它的作用是什么:将格式化输入写入指定的缓冲区

int snprintf(char *str, size_t size, const char *format, ...)
  • str是指向要写入的缓冲区的指针
  • size是要写入的字符的最大数量
  • format是一个格式化字符串,用于指定输出的格式
  • …是可变参数列表,用于传递变量值

在我的Json项目中,有这么一段代码:

static void dump(double value, string& out){// std::isfinite在头文件cmath中,用于判断浮点数是否是有限的// 即是否既不是无穷大(inf),也不是非数(NaN)//如果参数是有限的浮点数,则返回 true;否则,返回 false。if(std::isfinite(value)){char buf[32];// 在头文件cstdio中// 用于:将格式化的输入写入指定的缓冲区snprintf(buf, sizeof buf, "%.17g", value);}else{out += "null";}
}

在这里,我的使用是:

snprintf(buf, sizeof buf, "%.17g", value);

其中,我只需要再解释一下value就行了:snprintf将变量 value 格式化为一个字符串,也就是将value中所存储的数据更改为字符串类型。
但是我C语言学的不是很深,我对C不是很了解,我只想到了C++的stream头文件好像也是类似的作用,因此可以对它进行一个改写,使其更合乎C++代码的规范:

#include <sstream>
// 这个头文件用于规定输入输出的小数点位数
// 全称是“input/output manipulation”
#include <iomanip>std::ostringstream oss;
oss << std::setprecision(17) << std::fixed << value;
std::string str = oss.str();

接下来我们就说说sstream这个头文件的使用

sstream

sstream中有个十分关键的类,叫做stringstream,首先需要说下stringstream它究竟是什么:

stringstream 实际上是使用一个字符串作为内部的缓冲区。在内存中,这个缓冲区是一个字符数组,可以在其中存储任意长度的字符序列。

也就是说,我们能够将stringstream当作一个包装器,用于将字符串类型转换为其他类型。它能够存储任意的字符类型,并且能够很方便地将其转换为不同类型的数据,很安全也很方便。

方法作用
<<用于向流中插入数据
>>用于向流中提取数据
str()1.获取流中的内容 2.更改流中的内容
setstate()设置流的状态(状态有很多,使用的时候再去找资料吧)
clear()清除流的状态标识

本文只给出了stringstream的部分常用函数,它的函数很多,因为它的基类是std::basic_stringstream,再往底层走那些文档我就不是很能看得懂了。
这里就用一个例子来说明stringstream的使用:

#include <sstream>
#include <iostream>
#include <string>int main(){std::stringstream ss;// 向流中写入数据ss << "Hello World";// 获取流中的数据std::string out = ss.str();std::cout << out << std::endl;// 使用带参数的str对流中的内容进行替换ss.str("None");out = ss.str();std::cout << out << std::endl;// 更改流状态ss.setstate(std::ios_base::iostate::_S_badbit);// 重置流数据// 但是由于流状态已经出错了// 此时重置流数据无效ss << "Hello";out = ss.str();std::cout << out << std::endl;// 清除状态标识ss.clear();// 可以重置流数据了ss << "Hello";out = ss.str();std::cout << out << std::endl;
}

str()的使用

str()有两个版本:

  • 无参版本:str()函数返回stringstream对象当前的字符序列作为一个std::string对象
  • 有参版本:str(const std::string& s)函数将std::string类型的参数s作为stringstream对象的新内容,并清除原有内容

好像这个函数没有什么需要注意的地方:

#include <iostream>
#include <sstream>
#include <string>int main(){std::stringstream ss;ss.str("hello world");std::string out = ss.str();std::cout << out;
}

除了使用str()进行数据写入,我们还能够使用它重载的"<<"运算符进行数据写入
虽然str()和"<<”都有更改stringstream中数据的作用,但是它们的作用还是有所不同:str()是直接替换其中的,而"<<"是将输入的元素添加在原本的数据后面,于是我写了如下代码:

#include <iostream>
#include <sstream>
#include <string>int main(){std::stringstream ss;ss.str("hello world");std::string out = ss.str();std::cout << out << std::endl;ss << "??";out = ss.str();std::cout << out << std::endl;
}

运行结果取跟我想的不一样,我希望它是:

hello world
hello world??

实际上它是:

hello world
??llo world

stringstream中维护了一个流指针,str()会将流指针的位置重置至stringstream的首部,而<<是根据流指针的位置进行数据写入,因此就产生了数据覆盖
因此我们想要完成字符串的拼接可以这么写:

#include <sstream>
#include <iostream>int main(){std::stringstream ss;ss.str("hello ");// 拼接ss << ss.str() << "world";std::cout << ss.str();
}

还有很多种写法,反正宗旨都是注意流指针的位置

clear()的使用

这个函数其实用的也比较少,只有当stringstream出现异常状态的时候才需要使用,这里我们使用一段代码来说明:

#include <sstream>
#include <iostream>int main(){std::stringstream ss;// 先将ss置空ss.str("");// 手动增加流状态标识ss.setstate(std::ios_base::badbit);// 再次更改ssss << "Hello world";// 没输出,说明更改失败std::cout << ss.str() << std::endl;// 清除流的状态标识ss.clear();// 再次更改ssss << "Hello world";// 更改成功std::cout << ss.str() << std::endl;
}

这个情况只有在使用“<<”运算符才会出现,如果我们使用的str()进行数据的修改,不管它是什么状态都能够正常运行,代码如下

#include <sstream>
#include <iostream>int main(){std::stringstream ss;// 先将ss置空ss.str("");// 手动增加流状态标识ss.setstate(std::ios_base::badbit);// 再次更改ssss.str("Hello world");// 更改成功std::cout << ss.str() << std::endl;// 清除流的状态标识ss.clear();// 再次更改ssss.str("Hello world!!!");// 还是更改成功std::cout << ss.str() << std::endl;
}

这是因为:由于std::stringstream继承自std::basic_istream和std::basic_ostream,它继承了在流类中常见的成员函数,其中包括 str() 方法。str()方法用于获取或设置流中的字符串内容,而不涉及流的状态标识。因此,不管我们怎么设置流的状态标识,str()都能够正常获取和更改数据,这涉及了C++继承机制的知识点。

对于stringstream的疑惑

因为之前说,stringstream的输入输出操作是基于流指针的,于是我又编写了以下代码:

#include <sstream>
#include <iostream>int main(){std::stringstream ss;ss.str("Hello World");std::cout << ss.tellg() << '\n';// 清空ss.str("");ss << "Hello World";std::cout << ss.tellg();
}

发现:不管我怎么对ss进行操作,tellg()所输出的结果始终是0,那么,流指针操控stringstream的说法就不攻自破了,那么,是为什么呢?
所以我猜测,stringstream的底层是维护了一个计数器,因为查找gcc源码,在str()函数调用一直向下查,能找到这么一行:
![[289163feae27ce6d15d54b4130649d4a.png]]
因此我猜测是这个,但是我却没有办法去验证,所以只能记住这个特性了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/233023.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

泰坦陨落2找不到msvcr120文件的修复方法,分享多种解决方法

在玩泰坦陨落2这款游戏时&#xff0c;有些玩家可能会遇到找不到msvcr120.dll文件的问题。这个问题可能是由于游戏缺少必要的运行库导致的。下面我将分享一些解决这个问题的方法&#xff0c;希望对大家有所帮助。 一、问题分析 msvcr120.dll是Microsoft Visual C Redistributab…

MATLAB - 使用 MPC Designer 线性化 Simulink 模型

系列文章目录 前言 本主题介绍如何使用 MPC Designer 对 Simulink 模型进行线性化。为此&#xff0c;请从包含 MPC 控制器块的 Simulink 模型打开该应用程序。本例中使用 CSTR_ClosedLoop 模型。 open_system(CSTR_ClosedLoop) 在模型窗口中&#xff0c;双击 MPC 控制器模块。…

Vue中英文翻译小结

背景&#xff1a;时局艰难&#xff0c;后端开发被强制写了vue&#xff0c;这不有个需求是中英文翻译&#xff0c;特此记录下&#xff0c;该怎么个翻译法子。 先引入全局的路由国际化文件&#xff0c;zh.js 和 en.js 1.关于插值表达Button里面 {{ $t(reinsop.common.back) }} …

LazyIDA源码阅读

LazyIDA是一款IDA插件&#xff0c;项目地址GitHub - L4ys/LazyIDA: Make your IDA Lazy! 外部引用 from __future__ import division from __future__ import print_function from struct import unpack import idaapi import idautils import idcfrom PyQt5.Qt import QAppli…

【函数调用需要哪些开销,内联函数又做了什么?】

系列文章目录 欢迎大家订阅我的《计算机底层原理》、《自顶向下看Java》专栏&#xff0c;我会持续为大家输出优质内容&#xff0c;能够帮助到各位就是对我最大的鼓励&#xff01; 目录 系列文章目录 前言 一、函数调用需要哪些开销 1.压栈于弹栈开销&#xff1a; 2.寄存器保存于…

JJJ:组合数据类型2

文章目录 字典的创建和删除 p50字典的创建方式 字典元素的访问及遍历 p51字典操作的相关方法 p52字典生成式集合的创建与删除 p54集合的操作符 p55集合的操作方法、集合的遍历 p56列表、元组、字典、集合的区别 Python 3.11新特性结构模型匹配字典合并运算符 |同步迭代 字典的创…

element-ui 抽屉里面嵌套弹窗

当我们在element-ui 的Drawer 抽屉里面嵌套弹窗时&#xff0c;有时会出现关闭弹窗后&#xff0c;抽屉依然被遮罩层挡着的情况&#xff0c;解决方法是 在 Drawer 里面写 :append-to-body"true" 和 :close-on-click-modal"false"&#xff0c;在弹窗里面写 :a…

vue中的事件修饰符、表单双向数据绑定和计算属性

目录 一、事件修饰符 二、表单双向数据绑定 模拟双向数据绑定&#xff08;双向数据绑定底层原理&#xff09; 三、计算属性 计算属性和methods方法区别&#xff1f; 计算属性和watch区别&#xff1f; 一、事件修饰符 stop 阻止事件冒泡 prevent 阻止事件默认行为 ca…

Java常见原子性操作

在Java语言中&#xff0c;对基本数据类型的变量读取赋值操作都是原子性的&#xff0c;对引用类型的变量读取和赋值的操作也是原子性的&#xff0c;因此诸如此类的操作是不可被中断的&#xff0c;要么执行&#xff0c;要么不执行&#xff0c;正所谓一荣俱荣一损俱损。 原子操作…

Linux线程——互斥锁

概念 互斥量&#xff08;mutex&#xff09;从本质上来说是一把锁&#xff0c;在访问共享资源前对互斥量进行加锁&#xff0c;在访问完成后释放互斥量上的锁。对互斥量进行加锁后&#xff0c;任何其他试图再次对互斥量加锁的线程将会被阻塞直到当前线程释放该互斥锁。 如果释放…

【HCIP学习记录】OSPF之DD报文

1.OSPF报文格式 24字节 字段长度含义Version1字节版本&#xff0c;OSPF的版本号。对于OSPFv2来说&#xff0c;其值为2。Type1字节类型&#xff0c;OSPF报文的类型&#xff0c;有下面几种类型&#xff1a; 1&#xff1a;Hello报文&#xff1b;● 2&#xff1a;DD报文&#xff1…

美国联邦机动车安全标准-FMVSS

FMVSS标准介绍&#xff1a; FMVSS是美国《联邦机动车安全标准》&#xff0c;由美国运输部下属的国家公路交通安全管理局(简称NHTSA)具体负责制定并实施。是美国联邦政府针对机动车制定的安全标准&#xff0c;旨在提高机动车的安全性能&#xff0c;减少交通事故中的人员伤亡。F…

ubuntu无 root 权限安装 screen

网上的方法主要是如下图的方法&#xff0c;源码安装&#xff0c;但是我一直 make install失败显示没有权限 然后选择放弃&#xff0c;然后随便试了一下方法 2&#xff0c;成功 方法 1 方法 2 pip3 install screen结果&#xff1a;

生物识别应用指纹的算法是什么样的?有什么性能?

方案特点 • 采用金融级安全芯片 ACH512 的指纹模组&#xff0c;指纹和密码安全存储&#xff0c;云端数据安全传输 • 采用高性能指纹专用安全MCU芯片ACM32FP4&#xff0c;支持小点阵图像算法处理 • 支持80*64、88*112、96*96、160*160、192*192等像素传感器 • 已适配传…

Ubuntu系统使用Nginx搭建RTMP服务器

环境&#xff1a; 推流端 rockpi s 主控rk3308 运行ubuntu系统 服务端 ubuntu 播放器 VLC播放器 服务端安装依赖&#xff1a; apt-get install build-essential libpcre3 libpcre3-dev libssl-dev创建nginx编译目录&#xff1a; mkdir my_nginx_rtmp cd my_nginx_rtmp/下载 …

【Python基础】文件读写

文章目录 [toc]打开文件open()函数参数解析示例 文件路径绝对路径示例 相对路径示例 打开文件的模式常用模式 读文件示例 写文件示例 按行读写文件readline()示例 readlines()示例 writelines()示例 关闭文件示例finally语句示例 上下文管理器示例 自定义读写类示例 打开文件 …

计算机网络:物理层(编码与调制)

今天又学会了一个知识&#xff0c;加油&#xff01; 目录 一、基带信号与宽带信号 1、基带信号 2、宽带信号 3、选择 4、关系 二、数字数据编码为数字信号 1、非归零编码【NRZ】 2、曼彻斯特编码 3、差分曼彻斯特编码 4、归零编码【RZ】 5、反向不归零编码【NRZI】 …

查找Apple Watch的序列号有重要意思,主要有两种方法

如果你打算购买二手Apple Watch&#xff0c;你可能需要检查它的序列号或IMEI号&#xff0c;来确保可靠性。以下是如何从Apple Watch和iPhone中查找序列号。 在Apple Watch上查找序列号和IMEI 1、在Apple Watch上&#xff0c;按下手表表面的数字皇冠以打开应用程序网格或列表。…

【设计模式--行为型--访问者模式】

设计模式--行为型--访问者模式 访问者模式定义结构案例优缺点使用场景扩展分派动态分派静态分派双分派 访问者模式 定义 封装一些作用于某种数据结构中的各元素的操作&#xff0c;它可以在不改变这个数据结构的前提下定义作用于这些元素的新操作。 结构 抽象访问者角色&…

晶体管的工作状态判断和工作条件

晶体管是模拟电路中基础的器件&#xff0c;对于电子工程师来说&#xff0c;了解晶体管工作的条件和判断晶体管的工作状态都是非常基础的&#xff0c;本文将带大家一起学习或回顾一下。 一、晶体管工作的条件 1.集电极电阻Rc&#xff1a; 在共发射极电压放大器中&#xff0c;…