iostream的格式控制

  因为scanf和pritf能够很好的控制输入和输出的格式,所以我之前比较少使用iostream流进行格式化的输入输出,或者当用的时候再临时查看C++ Reference。现在,将iostream输入输出的格式控制总结记录如下。

iostream的输入格式控制

  正在施工中......

iostream的输出格式控制

格式控制标记

  对于iostream的输出格式控制而言,我们可以通过继承自ios_base的fmtflags类型变量来控制(一种使用位掩码表示流格式的标志类型),这个类型可以是以下成员常量的任意有效组合:

类型 常量 作用效果
独立标志 boolalpha 将布尔类型按照true和false的形式输出
showbase 在整数类型的值之前加上数字基数前缀
showpoint 输出浮点数时,显示小数点
showpos 输出数值时,显示正负号
skipws 跳过某些输入操作的前导空格
unitbuf 每次输出操作后刷新输出
uppercase 在某些输出情况下,使用大写字母替换小写字母,比如数字基数的前缀
数字基数 dec 使用十进制的形式读写整数值
hex 使用十六进制的形式读写整数值
oct 使用八进制的形式读写整数值
浮点型格式 fixed 使用定点表示法输出浮点数
scientific 使用科学计数法输出浮点数
格式调整 internal 内部分散对齐,从输出字符宽度内部的某个特定位置进行字符填充
left 左对齐,从输出字符宽度的左侧开始输出,其余位置填充字符
right 右对齐,从输出字符宽度的右侧开始输出,其余位置填充字符

  这些标记的使用可以通过setf函数生效,也可以直接使用<<操作符使之生效。

独立标志示例

  源代码:

#include<iostream>
using namespace std;
std::ios_base::fmtflags fmtflags_backup;
//备份cout的格式标志
void backupFormatflags(){
    fmtflags_backup = cout.flags();
}
//重置cout的格式标志
void resetFormatflags(){
    cout.setf(fmtflags_backup);
}
void testBoolalpha(){
    backupFormatflags();
    bool flag = true;
    cout << boolalpha << flag << endl;          //输出true
    resetFormatflags();
}
void testShowbase(){
    backupFormatflags();
    cout << showbase << hex << 12345 << endl;   //输出12345的十六进制表示0x3039,前面加0x
    resetFormatflags();
}
void testShowpoint(){
    backupFormatflags();
    cout << 12345.0 << endl;                    //输出12345  不加小数点
    cout << showpoint << 12345.0 << endl;       //输出12345.0 加小数点
    resetFormatflags();
}
void testShowpos(){
    backupFormatflags();
    cout << showpos << 12345 << endl;           //输出+12345,前面有正号
    resetFormatflags();
}
void testUppercase(){
    backupFormatflags();
    cout << uppercase << showbase << hex << 12345 << endl;      //输出0X3039,数字基数字符为十六进制,大写字母
    resetFormatflags();
}
int main(int argc, char const *argv[]){
    // 测试boolalpha
    testBoolalpha();
    //测试showbase
    testShowbase();
    //测试showpoint
    testShowpoint();
    //测试showpos
    testShowpos();
    //测试uppercase
    testUppercase();
    return 0;
}

  输出结果:

true
0x3039
12345
12345.0
+12345
0X3039

数字基数标记示例

  源代码:

#include<iostream>
using namespace std;
int main(int argc, char const *argv[]){
    //定义一个要输出显示的变量
    int num = 123456;
    cout << "八进制:" << oct << num << endl;           //输出八进制格式数字
    cout << "十进制:" << dec << num << endl;           //输出十进制格式数字
    cout << "十六进制:" << hex << num << endl;         //输出十六进制格式数字
    return 0;
}

  输出结果:

八进制:361100
十进制:123456
十六进制:1e240

浮点型格式标记示例

  源代码:

#include<iostream>
using namespace std;
int main(int argc, char const *argv[]){
    //定义一个要输出显示的变量
    double num = 12345.6789;
    cout << "混合小数点:" << fixed << num << endl;             //带小数点的一般输出方法
    cout << "科学计数法:" << scientific << num << endl;        //科学计数法
    return 0;
}

  输出结果:

带小数点:12345.678900
科学计数法:1.234568e+04

对齐格式调整标记示例

  源代码:

#include<iostream>
using namespace std;
int main(int argc, char const *argv[]){
    //定义一个要输出显示的变量
    int num = 12345;
    cout.fill('*');             //设置填充字符
    cout.width(15);             //设置输出宽度
    //添加了前缀的数字基数标记才能表现出和其他格式的不同指出
    cout << internal << showbase << hex << num << endl;

    cout.fill('*');             //设置填充字符
    cout.width(15);             //设置输出宽度
    cout << left << num << endl;//左对齐

    cout.fill('*');             //设置填充字符
    cout.width(15);             //设置输出宽度
    cout << right << num << endl;//右对齐
    return 0;
}

  输出结果:

0x*********3039
0x3039*********
*********0x3039

读取和设置格式

  因为格式控制标记的生效条件不一样,比如cout.width()只会对下一次生效,而数字基数的设置是长久生效,那么这就打乱了输出的格式控制。因此,如果我们要进行格式的控制,那么最好只在局部范围内进行改变,然后及时恢复格式。C++提供了flags()函数可以进行格式读取和设置,其中flags函数有两个重载:

//返回当前的格式标记
fmtflags flags() const;
//设置新的格式标记,然后返回原有的格式标记
fmtflags flags (fmtflags fmtfl);
//也可是使用setf函数设置特定的格式标记

  使用flags进行格式读取和设置的方法如下所示:

#include<iostream>
using namespace std;
int main(int argc, char const *argv[]){
    //定义一个要输出显示的变量
    int num = 12345;

    cout << "原始格式:" << num << endl;

    auto fmt = cout.flags();    //保留原有格式
    //指定格式进行输出
    cout << "格式调整:";
    cout.fill('*');             //设置填充字符
    cout.width(15);             //设置输出宽度
    cout << right << showbase << hex << num << endl;

    cout.flags(fmt);
    cout << "格式恢复:" << num << endl;
    return 0;
}

  输出结果:

原始格式:12345
格式调整:*********0x3039
格式恢复:12345

输出格式控制示例

  在实际使用中要对字节流按照两位十六进制(大写,不带基数)的格式进行输出,每一个字节之间使用空格隔开,并且每个字节输出两位的宽度(不足的位置填充0字符),对其输出的格式控制如下所示:

#include <bits/stdc++.h>
using namespace std;
int main() {
    vector<unsigned char> data = {0xA5, 0x5A, 0x16, 0xF0, 0x05, 0xDC, 0x05, 0xDD, 0x03, 0xE8, 0x05, 0xDF, 0x07, 0x76, 0x07, 0x5C, 0x07, 0xAD, 0x06, 0x3C, 0x83, 0xE3, 0xD4, 0xAA };

    auto fmtflags = cout.flags();
    for(int i = 0; i < data.size(); i++){
        cout.width(2);
        cout.fill('0');
        cout << hex << uppercase << (int)data[i] << " ";
    }
    cout << endl;
    cout.flags(fmtflags);

    return 0;
}

  输出结果:

A5 5A 16 F0 05 DC 05 DD 03 E8 05 DF 07 76 07 5C 07 AD 06 3C 83 E3 D4 AA 

当珍惜每一片时光~