阐明一下,我用的是 g ++7.1.0 编译器,规范库源代码也是这个版本的。
始终以来,咱们每次应用 cout 输入数据的时候,如果要换行,都晓得应用形如 cout << endl;
这样的模式,那么 endl 到底是什么呢,它是怎么样实现输入一个换行符的性能的,以前我没有思考过,但当初我想弄懂它,上面就一起看一下吧。
1.endl 操作符的实现
在规范库头文件 <ostream>
中,我找到了 endl 的操作符重载函数,如下:
template<typename _CharT, typename _Traits>
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 << oct
这样的模式,但它不会对缓冲区间接进行操作,它是对后续的数据输入进行格式化,相似 c 语言的 %d 一样,且操纵算子的实现形式与 endl 相似,只是 << 的返回类型与参数类型不一样而已,这里就不再多说。
操纵算子分为两类,一类是无参的,定义在 ios_base.h 头文件中,还有一类是有参的,定义在 iomanip 头文件中。
2.1 无参操纵算子
操纵算子 | 阐明 |
---|---|
boolalpha | 针对 bool 类型变量,不是输入 0 和 1,而是输入 true 或者 false |
noboolalpha | boolalpha 的反向操作 |
showbase | 在输入八进制或者十六进制的时候,加上 0x 这样的前缀,次要它要放在进制操作符的后面 |
noshowbase | showbase 的反向操作 |
showpoint | 强制打印小数点 |
noshowpoint | showpoint 的反向操作 |
showpos | 针对非负的数字,强制加上 + 号输入 |
noshowpos | showpos 的反向操作 |
skipws | 它是一个输出类操作符,作用是在输出时跳过空格,这一点与不应用 skipws 时是统一的 |
noskipws | 这里次要是 noskipws 会扭转 >> 的默认输出形式,会把空格,制表符等也读入 |
uppercase | 在输入十六进制这样的数据时,对外面的字母进行大写,留神它对输入字符类型或者字符串类型是不起作用的 |
nouppercase | uppercase 的反向操作 |
unitbuf | 每次输入当前都刷新缓冲区 |
nounitbuf | unitbuf 的反向操作 |
internal | 在设置了输入宽度的状况下,符号左对齐,值右对齐,两头应用空格填充 |
left | 在设置了输入宽度的状况下,输入整体左对齐,没有设置输入宽度,说对齐都是耍流氓 |
right | 在设置了输入宽度的状况下,输入整体右对齐,iostream 流默认右对齐 |
dec | 十进制输入,对浮点数不起成果,只对整型有成果 |
hex | 十六进制输入, 对浮点数不起成果,只对整型有成果 |
oct | 八进制输入,对浮点数不起成果,只对整型有成果 |
fixed | 定点十进制进行输入,默认输入 6 位小数位,小数位有余补 0,超出的四舍五入,保留 6 位 |
scientific | 迷信计数法输入 |
hexfloat | 十六进制模式输入浮点数 |
defaultfloat | 对浮点数输入复原默认状态 |
一个应用案例如下:
#include <iostream>
using namespace std;
int main()
{
// Initializing the integer
double x = 10.2333336;
// 将浮点数 x 以十六进制模式输入,且字母都为大写
cout << uppercase << hexfloat << x << endl;
cout.width(12);
double y = -11.222;
// 勾销指定的浮点数格局,按默认格局输入
cout << defaultfloat;
// 符号左对齐,数值右对齐,两头填充空格
cout << internal << y << endl;
return 0;
}
输入后果如下:
0X1.47777806A1DABP+3
- 11.222
2.2 有参操纵算子
有参的操纵算子实际上是在无参的根底上实现的,是对无参操纵算子的补充,且对无参操纵算子的应用起到了简化的作用。
首先还是看一看有参操纵算子有哪些,如下:
操纵算子 | 参数类型 | 阐明 |
---|---|---|
resetiosflags | ios_base::fmtflags,此类型是一个枚举类型,蕴含了上述的无参操纵算子,多的格局之间以单竖线分隔 | 输入输出都可应用,重置以后流的格局 |
setiosflags | ios_base::fmtflags | 输入输出都可应用,减少以后流的格局 |
setbase | int | 输入输出都可应用,设置进制,参数值可为 8,10,16,如果是其余值则示意应用默认的 |
setfill | 无固定类型,是一个函数模板 | 输入输出都可应用,设定对齐时的填充字符,虽说是模板,但参数个别倡议应用 char 类型 |
setprecision | int | 输入输出都可应用,设置精度,留神默认状况下这里的精度并不是指小数位,而是蕴含整数位在内,总共能够显示多少位数字,然而如果当时应用 fixed 指定了的话,那该精度就是单指小数位了 |
setw | int | 输入输出都可应用,设置宽度 |
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 <iomanip>
#include <iostream>
#include <time.h>
#include <sstream>
using namespace std;
void test01()
{locale loc_de = locale("en_US.utf-8");
cout.imbue(loc_de);
const string str("720000000000");
cout << put_money(str) << endl;
string str2;
cin.imbue(loc_de);
cin >> get_money(str2);// 这里要依照 imbue 设置的区域和编码进行输出,形如:72,000,000
cout << "str2=" << str2 << endl;
time_t t;
time(&t);
tm *tmp = localtime(&t);
cout << put_time(tmp, "%y %a") << endl;
tm time1;
istringstream iss("15:12:00 2021");
iss >> get_time(&time1, "%H:%M:%S %Y");
cout << "hour:" << time1.tm_hour << ',' << "min:" << time1.tm_min << ',' << "sec:" << time1.tm_sec << endl;
}
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 来示意,对于区域文化,这里就不开展阐明了。