cout格式化输出

转载于:cout格式化输出

在C语言中,我们一般用printf()函数来进行输出,通过输出字符串中的格式说明符(如%4.2d)可以很容易地格式化输出。而在C++中,为简便起见,往往不指定输出的格式,由系统根据数据的类型采取默认的格式,但有时也需要数据按我们指定的格式输出,比如以十六进制的形式输出一个整数等。有两种方法可以达到格式化输出的目的,一种是使用流对象的有关成员函数,还有一种是使用控制符方法,这两种方法殊途同归,它们的原理和起到的作用都是一样的,只不过使用形式不一样。

cout格式化输出常用函数及标志汇总

表1 用于控输出格式的流成员函数及控制符

流成员函数 作用相同的控制符 作用
precision(n) setprecision(n) 设置实数的精度为n位
width(n) setw(n) 设置字段宽度为n位
fill(c) setfill(c) 设置填充宇符c
setf(ios::state) setiosflags(ios::state) 设置输出格式状态,括号中应给出格式状态,内容与控制符setiosflags括号中的内容相同,如表2所示
unsetf(ios::state) resetioflags(ios::state) 终止已设置的输出格式状态,在括号中应指定内容


表2 设置格式状态的格式标志

格式标志 作用
ios::left 输出数据在本域宽范围内向左对齐
ios::right 输出数据在本域宽范围内向右对齐
ios::internal 数值的符号位在域宽内左对齐,数值右对齐,中间由填充字符填充
ios::dec 设置整数的基数为10
ios::oct 设置整数的基数为8
ios::hex 设置整数的基数为16
ios::showbase 强制输出整数的基数(八进制数以0打头,十六进制数以0x打头)
ios::showpoint 强制输出浮点数的小点和尾数0
ios::uppercase 在以科学记数法格式E和以十六进制输出字母时以大写表示
ios::showpos 对正数显示“+”号
ios::scientific 浮点数以科学记数法格式输出
ios::fixed 浮点数以定点格式(小数形式)输出
ios::boolalpha 以“true”/“false”的形式输出布尔值
ios::unitbuf 每次输出之后刷新所有的流
ios::stdio 每次输出之后清除stdout, stderr


用流对象的成员函数控制输出格式

我们可以使用用流对象的成员函数来控制输出格式。比如我们想要以十六进制来输出一个整形,设置字段宽度为8位,并用’*’来填充空白的话,可以使用以下代码:

#include <iostream>
using namespace std;
int main(){
    int a = 31;
    cout.width(8);
    cout.fill('*');
    cout.unsetf(ios::dec);
    cout.setf(ios::hex);
    cout << a << endl;
}
    
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

输出为:

******1f

使用控制符控制输出格式

我们也可以使用控制符来控制输出格式,这样就无需调用流的成员函数,可以直接在输出输入流中调用相关控制符,我们可以用以下代码实现上文中同样的输出格式:

#include <iostream>
#include <iomanip>  //不要忘记包含此头文件
using namespace std;
int main(){
    int a = 31;
    cout << setw(8) << setfill('*') << resetiosflags(ios::dec) << setiosflags(ios::hex) << a << endl;
}
    
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

注意:

  • 使用控制符时需要包含头文件<iomanip>。
  • 表2中的格式标志有些是互斥的(比如dec、hex和oct中只能选一),如果想改设置为互斥的另一状态,应当调用成员函数unsetf(对应于成员函数self)或resetiosflags(对应于控制符setiosflags),终止原来设置的状态,然后再设置其他状态。比如之前的例子中终止了默认的十进制(ios::dec),然后再设置了十六进制(ios::hex),如果不终止原来的十进制标志的话,输出仍然会以十进制输出。
  • 各个函数中成员函数width(n)和控制符setw(n)只对其后的第一个输出项有效,而其他函数及各个标志是对输出输入流一直生效的。
  • 表2中的格式标志在ios类中被定义为枚举值,每一个格式标志以一个bit的0或1代表(如下enum _Ios_Fmtflags所示),因此可以用位或运算符“|”组合多个格式标志,在流成员函数setf()/unsetf()以及控制符setioflags()/resetioflags()同时设置。比如:cout.setf(ios::dec | ios::showpos);
enum _Ios_Fmtflags 
    { 
      _S_boolalpha  = 1L << 0,
      _S_dec        = 1L << 1,
      _S_fixed      = 1L << 2,
      _S_hex        = 1L << 3,
      _S_internal   = 1L << 4,
      _S_left       = 1L << 5,
      _S_oct        = 1L << 6,
      _S_right      = 1L << 7,
      _S_scientific     = 1L << 8,
      _S_showbase   = 1L << 9,
      _S_showpoint  = 1L << 10,
      _S_showpos    = 1L << 11,
      _S_skipws     = 1L << 12,
      _S_unitbuf    = 1L << 13,
      _S_uppercase  = 1L << 14,
      _S_adjustfield    = _S_left | _S_right | _S_internal,
      _S_basefield  = _S_dec | _S_oct | _S_hex,
      _S_floatfield     = _S_scientific | _S_fixed,
      _S_ios_fmtflags_end = 1L << 16,
      _S_ios_fmtflags_max = __INT_MAX__,
      _S_ios_fmtflags_min = ~__INT_MAX__
    };
    
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

格式标志简化控制输出格式

在上述两种方法中,要设置格式标志位都需要调用函数(setf和setiosflags),比较麻烦,所幸C++还有一组关于格式标志的函数,可以直接在输入输出流中使用,比如要实现之前的输出格式我们可以这么写:

#include <iostream>
#include <iomanip> 
using namespace std;
int main(){
    int a = 31;
    cout << setw(8) << setfill('*') << hex << a << endl;
}
    
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

上面的hex就是这样的一个函数,除了hex,表2中的所有格式标志都通过这种方法设置,如果要终止只需标志名前加个“no”就可以,比如showpos和noshowpos(表2中前六项没有no版本)。
另外可以注意到,这里用hex设置十六进制的时候并不用像之前一样先终止十进制,这是为什么呢?先来看看hex的函数定义:

inline ios_base&
hex(ios_base& __base)
{
    __base.setf(ios_base::hex, ios_base::basefield);
    return __base;
}
    
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

可以看到hex其实是调用了setf函数,但这里的setf跟我们上面用到的setf函数不同,这是重载之后有两个形参的setf函数,其定义如下:

fmtflags
setf(fmtflags __fmtfl, fmtflags __mask)
{
      fmtflags __old = _M_flags;
      _M_flags &= ~__mask;
      _M_flags |= (__fmtfl & __mask);
      return __old;
}
    
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

可以看到这里setf先将mask所对应的位都置0,再将要设置的位置1。具体到hex函数,它是将_S_basefield(_S_dec | _S_oct | _S_hex)都先置0,再将_S_hex位置1。有了这个setf函数,我们在使用hex的时候就不需要先终止dec了,可以直接使用hex。

        <link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/markdown_views-ea0013b516.css">
            </div>

在C语言中,我们一般用printf()函数来进行输出,通过输出字符串中的格式说明符(如%4.2d)可以很容易地格式化输出。而在C++中,为简便起见,往往不指定输出的格式,由系统根据数据的类型采取默认的格式,但有时也需要数据按我们指定的格式输出,比如以十六进制的形式输出一个整数等。有两种方法可以达到格式化输出的目的,一种是使用流对象的有关成员函数,还有一种是使用控制符方法,这两种方法殊途同归,它们的原理和起到的作用都是一样的,只不过使用形式不一样。

cout格式化输出常用函数及标志汇总

表1 用于控输出格式的流成员函数及控制符

流成员函数 作用相同的控制符 作用
precision(n) setprecision(n) 设置实数的精度为n位
width(n) setw(n) 设置字段宽度为n位
fill(c) setfill(c) 设置填充宇符c
setf(ios::state) setiosflags(ios::state) 设置输出格式状态,括号中应给出格式状态,内容与控制符setiosflags括号中的内容相同,如表2所示
unsetf(ios::state) resetioflags(ios::state) 终止已设置的输出格式状态,在括号中应指定内容


表2 设置格式状态的格式标志

格式标志 作用
ios::left 输出数据在本域宽范围内向左对齐
ios::right 输出数据在本域宽范围内向右对齐
ios::internal 数值的符号位在域宽内左对齐,数值右对齐,中间由填充字符填充
ios::dec 设置整数的基数为10
ios::oct 设置整数的基数为8
ios::hex 设置整数的基数为16
ios::showbase 强制输出整数的基数(八进制数以0打头,十六进制数以0x打头)
ios::showpoint 强制输出浮点数的小点和尾数0
ios::uppercase 在以科学记数法格式E和以十六进制输出字母时以大写表示
ios::showpos 对正数显示“+”号
ios::scientific 浮点数以科学记数法格式输出
ios::fixed 浮点数以定点格式(小数形式)输出
ios::boolalpha 以“true”/“false”的形式输出布尔值
ios::unitbuf 每次输出之后刷新所有的流
ios::stdio 每次输出之后清除stdout, stderr


用流对象的成员函数控制输出格式

我们可以使用用流对象的成员函数来控制输出格式。比如我们想要以十六进制来输出一个整形,设置字段宽度为8位,并用’*’来填充空白的话,可以使用以下代码:

#include <iostream>
using namespace std;
int main(){
    int a = 31;
    cout.width(8);
    cout.fill('*');
    cout.unsetf(ios::dec);
    cout.setf(ios::hex);
    cout << a << endl;
}
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

输出为:

******1f

使用控制符控制输出格式

我们也可以使用控制符来控制输出格式,这样就无需调用流的成员函数,可以直接在输出输入流中调用相关控制符,我们可以用以下代码实现上文中同样的输出格式:

#include <iostream>
#include <iomanip>  //不要忘记包含此头文件
using namespace std;
int main(){
    int a = 31;
    cout << setw(8) << setfill('*') << resetiosflags(ios::dec) << setiosflags(ios::hex) << a << endl;
}
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

注意:

  • 使用控制符时需要包含头文件<iomanip>。
  • 表2中的格式标志有些是互斥的(比如dec、hex和oct中只能选一),如果想改设置为互斥的另一状态,应当调用成员函数unsetf(对应于成员函数self)或resetiosflags(对应于控制符setiosflags),终止原来设置的状态,然后再设置其他状态。比如之前的例子中终止了默认的十进制(ios::dec),然后再设置了十六进制(ios::hex),如果不终止原来的十进制标志的话,输出仍然会以十进制输出。
  • 各个函数中成员函数width(n)和控制符setw(n)只对其后的第一个输出项有效,而其他函数及各个标志是对输出输入流一直生效的。
  • 表2中的格式标志在ios类中被定义为枚举值,每一个格式标志以一个bit的0或1代表(如下enum _Ios_Fmtflags所示),因此可以用位或运算符“|”组合多个格式标志,在流成员函数setf()/unsetf()以及控制符setioflags()/resetioflags()同时设置。比如:cout.setf(ios::dec | ios::showpos);
enum _Ios_Fmtflags 
    { 
      _S_boolalpha  = 1L << 0,
      _S_dec        = 1L << 1,
      _S_fixed      = 1L << 2,
      _S_hex        = 1L << 3,
      _S_internal   = 1L << 4,
      _S_left       = 1L << 5,
      _S_oct        = 1L << 6,
      _S_right      = 1L << 7,
      _S_scientific     = 1L << 8,
      _S_showbase   = 1L << 9,
      _S_showpoint  = 1L << 10,
      _S_showpos    = 1L << 11,
      _S_skipws     = 1L << 12,
      _S_unitbuf    = 1L << 13,
      _S_uppercase  = 1L << 14,
      _S_adjustfield    = _S_left | _S_right | _S_internal,
      _S_basefield  = _S_dec | _S_oct | _S_hex,
      _S_floatfield     = _S_scientific | _S_fixed,
      _S_ios_fmtflags_end = 1L << 16,
      _S_ios_fmtflags_max = __INT_MAX__,
      _S_ios_fmtflags_min = ~__INT_MAX__
    };
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

格式标志简化控制输出格式

在上述两种方法中,要设置格式标志位都需要调用函数(setf和setiosflags),比较麻烦,所幸C++还有一组关于格式标志的函数,可以直接在输入输出流中使用,比如要实现之前的输出格式我们可以这么写:

#include <iostream>
#include <iomanip> 
using namespace std;
int main(){
    int a = 31;
    cout << setw(8) << setfill('*') << hex << a << endl;
}
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

上面的hex就是这样的一个函数,除了hex,表2中的所有格式标志都通过这种方法设置,如果要终止只需标志名前加个“no”就可以,比如showpos和noshowpos(表2中前六项没有no版本)。
另外可以注意到,这里用hex设置十六进制的时候并不用像之前一样先终止十进制,这是为什么呢?先来看看hex的函数定义:

inline ios_base&
hex(ios_base& __base)
{
    __base.setf(ios_base::hex, ios_base::basefield);
    return __base;
}
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

可以看到hex其实是调用了setf函数,但这里的setf跟我们上面用到的setf函数不同,这是重载之后有两个形参的setf函数,其定义如下:

fmtflags
setf(fmtflags __fmtfl, fmtflags __mask)
{
      fmtflags __old = _M_flags;
      _M_flags &= ~__mask;
      _M_flags |= (__fmtfl & __mask);
      return __old;
}
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

可以看到这里setf先将mask所对应的位都置0,再将要设置的位置1。具体到hex函数,它是将_S_basefield(_S_dec | _S_oct | _S_hex)都先置0,再将_S_hex位置1。有了这个setf函数,我们在使用hex的时候就不需要先终止dec了,可以直接使用hex。

        <link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/markdown_views-ea0013b516.css">
            </div>

猜你喜欢

转载自blog.csdn.net/xc13212777631/article/details/80549575
今日推荐