C++提供的输出格式,可以简单理解成一个个标志位。我们对输出格式的控制,其实就是将相应的标志位打开、关闭和设置。内部的实现原理,不必太过深究,会用就行。但需要注意,有些标志位只需要打开或者关闭即可,比如左对齐、右对齐,但是,有些标志位则是需要具体数值或者字符,比如设置宽度和填充字符。
对这些标志位的修改(打开或关闭),因为历史原因,方式有很多。究竟哪种方式好,没有定论。但是我们在写程序时,尽量使用同一种设置方式。学习的时候,也只需要学习一种最适合你的即可。
想要控制输出格式,C++提供的方法很多,有人将其分为两种:一种是控制流的成员函数设置,另一种是利用控制符设置函数setiosflags、setfill、setw等。
但是我认为分为三种更合适,setiosflags应该单独作为一种,且最不推荐,为何,后面会做解释。
1、用cout的成员函数进行格式设置 这种方式,需用用到setf函数,该函数有两个版本,一个只含一个参数,另一个含有两个参数。参数为各个控制位对应的枚举值,即我们经常见到的 std::ios_base::left、std::ios_base::showbase等。其对应的取消设置函数为unsetf。
例如:想指定宽度为10,左对齐,不足位用‘*’填充,用十六进制打印出来,且前面要输出进制的前缀。则可以如下:
int nValue = https://www.it610.com/article/10;
cout.width(10);
cout.fill('*');
cout.setf(std::ios_base::showbase);
//可以用"|"运算符
cout.setf(std::ios_base::hex, std::ios_base::basefield);
cout.setf(std::ios_base::left, std::ios_base::adjustfield);
cout << nValue << endl;
执行结果为:
文章图片
setf的注意事项 【C++基础|C++基础(三) 格式控制 setf、setiosflags等详解及避坑】C++将控制符分为了两类:
文章图片
第一类是独立的控制符号,如showbase、showpos等,这些,用setf只有一个参数的版本;
文章图片
另一类,为组合控制符号,如hex、left等,这些,需要用setf两个参数的版本:第一个参数为left等,第二个参数为其对应的组合值如adjustfield等,如下:
文章图片
如上面的例子,想设置左对齐和十六进制,只能:
cout.setf(std::ios_base::left, std::ios_base::adjustfield);
cout.setf(std::ios_base::hex, std::ios_base::basefield);
2、用setiosflags函数设置相应控制位 想使用该函数,需要包含头文件#include
setiosflags函数有一定的限制,只能打开和关闭相应标志位,对于那些需要提供具体数值或者字符的格式,有些无能为力。
其功能,可以理解成和setf类似,只不过它不是cout的成员函数,位于std名称空间,用起来比setf要略微方便一些。
但是!其只有setf单参数有效的控制位有用,比如上面的hex,就没有效果。
setiosflags函数的参数和setf一样,可以用"|"运算符指定多个,也可以连续设置。
上面的例子,将左对齐改为从中间填充,可以用如下代码实现:
using std::cout;
using std::endl;
int nValue = https://www.it610.com/article/10;
cout.width(10);
cout.fill('*');
cout.setf(std::ios_base::hex, std::ios_base::basefield);
//cout << std::setiosflags(std::ios_base::showbase | std::ios_base::internal);
//与下面一行代码效果相同
cout << std::setiosflags(std::ios_base::showbase) << std::setiosflags(std::ios_base::internal);
cout << nValue << endl;
执行结果为:
文章图片
为什么单独列出来,因为这个标志位设置函数,有个巨大坑。
setiosflags的局限性 前面已经介绍了控制符号分为两类,setiosflags函数只能设置独立的控制符,即setf单参数版本设置的那些控制符。其他的组合控制符,查阅了很多资料,它好像无能为力。
所以,这里将setiosflags单独列出来,作为一个警告!
3、直接用控制符设置(本人最习惯) 除了以上两种方式外,为了更加便捷操作,可以直接使用控制符。
控制符,也需要加上头文件#include
实现2中的效果,可以如下实现:
using std::cout;
using std::endl;
int nValue = https://www.it610.com/article/10;
cout << std::setw(10) << std::setfill('*');
cout << std::hex << std::showbase << std::left;
cout << nValue << endl;
执行结果为:
文章图片
甚至,所有格式控制和最后的nValue输出,可以合并成一行:
cout << std::setw(10) << std::setfill('*') << std::hex << std::showbase << std::internal << nValue << endl;
是不是很方便?
下面,开始介绍各个控制符的具体含义。
考虑到现在越来越多的程序开始使用宽字节(wchar_t)进行编码,所以后面的例子中将会使用wcout而不是cout。对于格式控制,不管是wcout还是cout,都完全一致。
以下代码如果想要copy至本地编译,请加上两行代码: using std::endl;
using std::wcout;
(1)setw、setfill、left、internal、right、showpos、noshowpos 这七个控制符里面,前五个是使用频率最高的,后两个是为了说明internal加到此处的。
这里面,只有setw设置后仅对下一个项目(可以理解成下一个有效输出)有效,其他的控制符一经设置一直有效,直到修改与其关联的控制符。
setw:设置宽度,为函数,参数为int型数值;
setfill:设置填充字符,为函数,参数为字符,默认填充字符是空格;
left:左对齐,即数字显示在左边,不够的再用setfill设置的字符填充;
right:右对齐,即数字显示在右边,不够的再在左侧用setfill设置的字符填充;默认对齐方式是右对齐;
internal:填充字符放到符号(正负号)和数字中间;
showpos:显示非负数字前的正号(+,pos为positive的缩写);
noshowpos:不显示非负数字前的正号,默认的是不显示。
wcout << L"----------------setw、setfill、left、internal、right、showpos、noshowpos----------------" << endl;
double dValue1 = -23.457;
double dValue2 = 3.56;
wcout << std::setfill(L'*');
int nWidth = 10;
wcout << std::setw(nWidth) << dValue2 << endl;
wcout << std::setw(nWidth) << std::left << dValue1 << endl;
wcout << std::setw(nWidth) << std::right << dValue1 << endl;
wcout << std::setw(nWidth) << std::internal << std::showpos << dValue2 << endl;
wcout << std::right << std::noshowpos;
执行结果:
文章图片
(2)setprecision、fixed、scientific setprecision:设置数字精度;
fixed:浮点数设置成普通的小数显示;
scientific:浮点数用科学计数法。
首先看一下fixed和scientific,普通的小数表示和科学计数法,很简单。
double dValue = https://www.it610.com/article/2563.54785243568914255;
wcout << dValue << endl;
wcout << std::scientific << dValue << endl;
执行结果为:
文章图片
setprecision需要注意
setprecision,也有一些需要注意的地方,看如下代码:
double d1 = 2.222222;
double d2 = 55.555555;
wcout << std::setprecision(3);
wcout << d1 << endl;
wcout << d2 << endl;
执行结果为:
文章图片
是不是与期待的有点不同?很可能是希望保留两位小数,结果55.555555成了55.6。
这里,setprecision设置的是整个数值的有效位数,而不是小数部分的有效位数。
想要设置固定的有效小数位,怎么办呢?与std::fixed控制符一起使用即可。如下:
double d1 = 2.222222;
double d2 = 55.555555;
wcout << std::setprecision(3) << std::fixed;
wcout << d1 << endl;
wcout << d2 << endl;
执行结果为:
文章图片
保留三位小数,注意,是四舍五入原则。
(3)showpoint、noshowpoint showpoint:对于小数部分为0的浮点数,显示小数点,并且根据设置的精度,补充小数末尾部分的0;
noshowpoint:与showpoint相反
这个控制符也有一些需要注意,如果设置了setprecision和std::fixed(其实只需要设置std::fixed即可,setprecision有默认值,一般为6),即便不设置showpoint,也会显示小数末尾的0。但是仅设置setprecision不行,如:
double dValue = https://www.it610.com/article/22.1;
wcout << std::setprecision(5) << dValue << endl;
//仅设置了setprecision,不会显示末尾0
wcout << std::fixed << dValue << endl;
执行结果为:
文章图片
如果未设置std::fixed,仅设置std::setprecision,想要显示小数末尾部分的0,则可以用std::showpoint。
需要注意,此时的setprecision表示的精度,不是小数部分,而是整个数值。如下:
double dValue = https://www.it610.com/article/22.1;
wcout << std::setprecision(5) << std::showpoint << dValue << endl;
执行结果如下:
文章图片
(4)oct、dec、hex、showbase以及noshowbase oct:八进制,前缀为:0;
dec:十进制,没有前缀,为进制的默认值;
hex:十六进制,前缀为:0x
showbase:显示进制的前缀;
noshowbase:不显示进制前缀。
这些控制符,都是一经设置一直有效。
int nValue_dec = 10;
wcout << std::oct << nValue_dec << endl;
//八进制,默认不显示前缀
wcout << std::showbase << nValue_dec << endl;
//打开前缀,还是输出上一行设置的八进制
wcout << std::hex << nValue_dec << endl;
//十六进制,已设置过现实显示前缀
wcout << std::dec << nValue_dec << endl;
//十进制,没有前缀
wcout << std::noshowbase << nValue_dec << endl;
执行结果:
文章图片
(5)boolalpha、noboolalpha boolalpha:将bool类型的变量输出为'true'或者'false'字样。
boolalpha:将bool类型的变量输出为1和0字样,默认为noboolalpha。
wcout << L"---------------------------boolalpha、noboolalpha----------------------------------" << endl;
bool bTrue = true;
bool bFalse = false;
wcout << bTrue << endl;
//1
wcout << bFalse << endl;
//0
wcout << std::boolalpha << bTrue << endl;
//true
wcout << bFalse << endl;
//false
wcout << std::noboolalpha << bTrue << endl;
//1
执行结果:
文章图片
(6)uppercase、nouppercase uppercase:对于进制前缀、十六进制a-f和浮点数科学计数法的字母e,均显示大写字母;
nouppercase:对于进制前缀、十六进制a-f和浮点数科学计数法的字母e,均显示小写字母,为默认值;
注意:对其他的(包括浮点数的true和false)无影响。
int nValue = https://www.it610.com/article/10;
bool bValue = https://www.it610.com/article/true;
double dValue = https://www.it610.com/article/2.354;
wcout << std::boolalpha << std::hex << std::showbase << std::scientific;
wcout << nValue << endl;
wcout << bValue << endl;
wcout << dValue << endl;
wcout << std::uppercase;
wcout << nValue << endl;
wcout << bValue << endl;
wcout << dValue << endl;
wcout << std::nouppercase;
执行结果为:
文章图片
推荐阅读
- C++|(C++)cout格式化输出示例
- c++|使用结构体数组求10个学生三门课总平均成绩,及最高分学生信息
- C++|cout.setf()
- c++|C++20三路比较运算符
- C++基础学习|C++学习必备网站推荐收藏
- 动态规划|AcWing 271. 杨老师的照相排列(简单DP)+ 十一届蓝桥杯B组试题E--矩阵
- leetcode|Leetcode二分查找12:1351. 统计有序矩阵中的负数
- 哈希|Leetcode二分查找11:1346. 检查整数及其两倍数是否存在
- 数据结构与算法|数据结构与性质(2)栈(stack)基础板子