热门标签 | HotTags
当前位置:  开发笔记 > 程序员 > 正文

c++中endl操作符以及它的兄弟们

说明一下,我用的是g++7.1.0编译器,标准库源代码也是这个版本的。一直以来,我们每次使用cout输出数据的时候,如果要换行,都知道使用形如cout

说明一下,我用的是g++7.1.0编译器,标准库源代码也是这个版本的。


一直以来,我们每次使用cout输出数据的时候,如果要换行,都知道使用形如cout <这样的形式,那么endl到底是什么呢,它是怎么样实现输出一个换行符的功能的,以前我没有思考过,但现在我想弄懂它,下面就一起看一下吧。



1.endl操作符的实现

在标准库头文件中,我找到了endl的操作符重载函数,如下:

template
inline basic_ostream<_CharT, _Traits>&
endl(basic_ostream<_CharT, _Traits>& __os)
{ return flush(__os.put(__os.widen('\n'))); }

它是一个内联的函数模板,是一个全局的函数模板,endl正是它的函数名,它的作用是往缓冲区写入一个换行符并且立即从缓冲区刷新到外部设备中。

那么endl是怎么与<<操作符关联起来的呢,我们在ostream头文件ostream类的声明中又发现了以下代码:

__ostream_type&
operator<<(__ostream_type& (*__pf)(__ostream_type&))
{
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// DR 60. What is a formatted input function?
// The inserters for manipulators are *not* formatted output functions.
return __pf(*this);
}

这个操作符的入参是一个__ostream_type& (*__pf)(__ostream_type&)类型的函数指针,这个类型与endl的类型是一致的,从而,我们现在知道了endl的实现过程。

与endl同样实现的总共是亲兄弟三个,他们类型一样,且都是对缓冲区进行操作,如下:










操作符说明
endl输出一个换行符到缓冲区,且即时刷新到外部设备
ends输出一个空字符到缓冲区
flush调用flush函数,把数据从缓冲区刷新到外部设备


2. 格式化操作符

说完endl的亲兄弟,接下来说一说它的堂兄弟们,那就是格式化操作符,在某些书籍上也叫做操纵算子,操纵算子用法与endl一样,也是形如cout <这样的形式,但它不会对缓冲区直接进行操作,它是对后续的数据输出进行格式化,类似c语言的%d一样,且操纵算子的实现方式与endl类似,只是<<的返回类型与参数类型不一样而已,这里就不再多说。

操纵算子分为两类,一类是无参的,定义在ios_base.h头文件中,还有一类是有参的,定义在iomanip头文件中。



2.1 无参操纵算子



















































操纵算子说明
boolalpha针对bool类型变量,不是输出0和1,而是输出true或者false
noboolalphaboolalpha的反向操作
showbase在输出八进制或者十六进制的时候,加上0x这样的前缀,主要它要放在进制操作符的前面
noshowbaseshowbase的反向操作
showpoint强制打印小数点
noshowpointshowpoint的反向操作
showpos针对非负的数字,强制加上+号输出
noshowposshowpos的反向操作
skipws它是一个输入类操作符,作用是在输入时跳过空格,这一点与不使用skipws时是一致的
noskipws这里主要是noskipws会改变>>的默认输入方式,会把空格,制表符等也读入
uppercase在输出十六进制这样的数据时,对里面的字母进行大写,注意它对输出字符类型或者字符串类型是不起作用的
nouppercaseuppercase的反向操作
unitbuf每次输出以后都刷新缓冲区
nounitbufunitbuf的反向操作
internal在设置了输出宽度的情况下,符号左对齐,值右对齐,中间使用空格填充
left在设置了输出宽度的情况下,输出整体左对齐,没有设置输出宽度,说对齐都是耍流氓
right在设置了输出宽度的情况下,输出整体右对齐,iostream流默认右对齐
dec十进制输出,对浮点数不起效果,只对整型有效果
hex十六进制输出,对浮点数不起效果,只对整型有效果
oct八进制输出,对浮点数不起效果,只对整型有效果
fixed定点十进制进行输出,默认输出6位小数位,小数位不足补0,超出的四舍五入,保留6位
scientific科学计数法输出
hexfloat十六进制形式输出浮点数
defaultfloat对浮点数输出恢复默认状态

一个使用案例如下:

#include

using namespace std;

int main()
{

// Initializing the integer
double x = 10.2333336;

//将浮点数x以十六进制形式输出,且字母都为大写
cout <
cout.width(12);
double y = -11.222;
//取消指定的浮点数格式,按默认格式输出
cout <
//符号左对齐,数值右对齐,中间填充空格
cout <
return 0;
}

输出结果如下:

0X1.47777806A1DABP+3
- 11.222


2.2 有参操纵算子

有参的操纵算子实际上是在无参的基础上实现的,是对无参操纵算子的补充,且对无参操纵算子的使用起到了简化的作用。

首先还是看一看有参操纵算子有哪些,如下:



































操纵算子参数类型说明
resetiosflagsios_base::fmtflags,此类型是一个枚举类型,包含了上述的无参操纵算子,多的格式之间以单竖线分隔输入输出都可使用,重置当前流的格式
setiosflagsios_base::fmtflags输入输出都可使用,增加当前流的格式
setbaseint输入输出都可使用,设置进制,参数值可为8,10,16,如果是其他值则表示使用默认的
setfill无固定类型,是一个函数模板输入输出都可使用,设定对齐时的填充字符,虽说是模板,但参数一般建议使用char类型
setprecisionint输入输出都可使用,设置精度,注意默认情况下这里的精度并不是指小数位,而是包含整数位在内,总共可以显示多少位数字,但是如果事先使用fixed指定了的话,那该精度就是单指小数位了
setwint输入输出都可使用,设置宽度
get_money有两个参数,第一个参数是一个函数模板,但根据iomanip头文件,它应该是一个long double类型或者string类型,此时该参数其实是一个出参,输入的数据存储在该参数里面,第二个参数是一个bool类型,表示是否国际化输入使用,根据设置的区域文化和编码以及输入的对应的货币表达式,获取相应的数据
put_money有两个参数,第一个参数是一个函数模板,但根据iomanip头文件,它应该是一个long double类型或者string类型,第二个参数是一个bool类型,表示是否国际化输出使用,根据设置的区域文化和编码,输出相应的货币表达式
put_time第一个参数是const std::tm类型指针,第二个类型是对时间进行格式化的格式字符串根据第二个参数指定格式输出tm中数据
get_time第一个参数是const std::tm类型指针,第二个类型是对时间进行格式化的格式字符串根据第二个参数指定格式把数据填充到tm中

带参数的这些操作函数,前面6个其实是比较好理解的,但是后面四个用起来就比较麻烦了,而且单独使用也是不起作用的,下面我们就后面四个操作符,看一下使用案例,如下:

#include
#include
#include
#include
using namespace std;
void test01()
{
locale loc_de = locale("en_US.utf-8");
cout.imbue(loc_de);
const string str("720000000000");
cout <
string str2;
cin.imbue(loc_de);
cin >> get_money(str2);//这里要按照imbue设置的区域和编码进行输入,形如:72,000,000
cout <<"str2=" <
time_t t;
time(&t);
tm *tmp = localtime(&t);
cout <
tm time1;
istringstream iss("15:12:00 2021");
iss >> get_time(&time1, "%H:%M:%S %Y");
cout <<"hour:" <}
int main()
{
test01();
return 0;
}

输出显示如下:

[root@mylinux ~]# ./a.out
7,200,000,000.00
12,00,00 #注意这里是屏幕输入的
str2=120000
21 Thu
hour:15,min:12,sec:0
[root@mylinux ~]#

后面四个函数的使用就涉及到程序国际化以及区域文化的问题,比如浮点数,在我们大中国是72000.12,那么到了美国可能又是用72,000.12来表示,关于区域文化,这里就不展开说明了。


在这里插入图片描述



推荐阅读
  • 本文分享了作者在不同版本的Ubuntu系统上尝试编译VLC for Android的经历,包括遇到的技术难题及解决方案,旨在帮助开发者避免常见的编译问题。 ... [详细]
  • 通过网上的资料我自己的实际内核编译,我把对Linux内核编译的过程写在这里,也许对其他的Linux爱好者的编译学习有些帮助,其中很大部分是 ... [详细]
  • Linux环境下MySQL的安装与配置
    本文详细介绍了在Linux系统上安装和配置MySQL的步骤,包括安装前的准备工作、下载和解压安装包、初始化数据库、配置文件编辑、启动服务以及设置开机自启动等。 ... [详细]
  • 本文详细介绍了在 CentOS 7 系统中安装 Python 3.7 的步骤,包括编译工具的安装、Python 3.7 源码的下载与编译、软链接的创建以及常见错误的处理方法。 ... [详细]
  • 本文介绍了如何在Linux系统中将命令添加到PATH环境变量中,以便在任何位置都能直接运行这些命令。PATH是一个包含多个目录路径的字符串变量,当输入不带路径的命令时,系统会在这些路径中查找并执行相应的命令。 ... [详细]
  • 本文详细介绍了在单片机编程中常用的几个C库函数,包括printf、memset、memcpy、strcpy和atoi,并提供了具体的使用示例和注意事项。 ... [详细]
  • C++中构造函数与析构函数的虚函数特性及多态行为分析
    本文探讨了C++中构造函数和析构函数是否可以定义为虚函数,以及它们在多态行为中的表现。通过实例代码详细解释了虚函数表指针的初始化时机及其对多态的影响。 ... [详细]
  • c#  项目文件,C#viual studio使用方法
    一、项目文件1)Properties节点下主要存放的是当前程序集相关的信息,如版本号、标题等。双击”Properties“,打开如下项目属 ... [详细]
  • 本文总结了软件工程课程M1和M2阶段的个人收获,包括项目开发中的技术学习、团队协作及管理经验。同时,对《构建之法》一书中的相关问题进行了理解和分析。 ... [详细]
  • Django与Python及其他Web框架的对比
    本文详细介绍了Django与其他Python Web框架(如Flask和Tornado)的区别,并探讨了Django的基本使用方法及与其他语言(如PHP)的比较。 ... [详细]
  • 本文详细介绍了Sleep函数的基本概念、使用方法及其背后的实现原理。适合对Sleep函数的使用和实现感兴趣的开发者阅读。通过本文,您将了解如何在不同操作系统中使用Sleep函数,以及其在多线程编程中的重要性。 ... [详细]
  • pypy 真的能让 Python 比 C 还快么?
    作者:肖恩顿来源:游戏不存在最近“pypy为什么能让python比c还快”刷屏了,原文讲的内容偏理论,干货比较少。我们可以再深入一点点,了解pypy的真相。正式开始之前,多唠叨两句 ... [详细]
  • 本文介绍了如何在Linux系统中获取库源码,并在从源代码编译软件时收集所需的依赖项列表。 ... [详细]
  • 本文提供了初级计算机考试的第二部分题目及其详细解析,涵盖了单项选择题,涉及计算机存储、硬件、软件等多个方面的基础知识。 ... [详细]
  • 本文详细介绍了TypeScript中的各种数据类型,包括基本类型、数组、元组、枚举、any、void、never以及类型断言,并提供了示例代码及其编译结果。 ... [详细]
author-avatar
手机用户2502908237
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有