1 C函数printf

最常见的是C语言提供的printf函数,可以在格式化字符串中设置打印的各种类型、进制和精度等。这里不再细讲了。

2 std::cout+属性设置函数

cout是C++默认的打印函数,可以支持各个基本类型的打印。我们可以通过**<ios>****<iomanip>**中的函数设置cout的打印属性,达到与printf格式化字符串一样的功能。当然它们也可以用于std::cin。常用的函数有:

  • 设置整数输入输出进制:std::dec, std::hex, std::oct
  • 修改浮点输入/输出的默认格式:std::fixed, std::scientific, std::hexfloat, std::defaultfloat
  • 设置打印精度:std::setprecision(n)
  • 设置打印长度:std::setw(n)

示例

  1. //5位长度,两位精度,即小数点后一位
  2. std::cout << "float number is " << std::setw(5)
  3. << std::setprecision(2) << 5.13 << endl;

3 std::format()

在C++20引入了<format>库,我们可以用std::format()代替那么多属性设置函数,达到和printf格式化字符串类似的功能。
std::format使用**{}**标识一个需要被打印的元素,format最终返回一个格式化后的string类型,可以交给std::cout打印出来。

基于属性设置

可以在{}中设置如下的属性:

  1. {[index]:[[fill]align][sign][#][0][width][.precision][type]}
  • index:打印顺序,指定此处使用后面哪个参数
  • fill:设置对齐方式之后的填充字符
    • 默认:空白字符
  • align:对齐方式:
    • 左对齐:<
    • 右对齐:>
    • 中间对齐:^
  • sign:设置在正数前面打印什么字符,一般为+或空白
  • :表示替代格式,用于常见的数值类型,在value前添加0x、0b、0等进制标志

  • 0:对齐的填充字符为数字0,不使用fill中字符
  • width:设置打印长度
  • .precision:设置精度
  • type:打印参数的类型
    • 浮点数类型:
      • f:浮点数
      • e:科学计数法
      • g:通用格式
    • 整数类型:
      • x:十六进制
      • b:二进制
      • o:八进制
      • d:十进制
    • bool类型:
      • s:true 、false
      • b、c、d、o、x:1、0
    • c:char
    • s:string
    • p:指针地址0x

需要注意:有些属性并不适用于某些类型,假如在{}中设置了不符合的属性,fotmat函数会抛出异常std::format_error

示例如下:

  1. std::cout << std::format("{:*<7}|{:*<7}|{:*>7}|{:*>7}|{:*>7}\n", 1,-.2,"str",'c',true);
  2. // Centered alignment + 0 formatting option for numbers
  3. std::cout << std::format("{:^07}|{:^07}|{:^7}|{:^7}|{:^7}\n", 1, -.2, "str", 'c', true);
  4. //输出为
  5. //1******|-0.2***|****str|******c|***true
  6. //0000001|-0000.2| str | c | true
  7. std::cout << std::format("Default: {:.2}, fixed: {:.2f}, scientific: {:.2e}, "
  8. "general: {:.2g}\n", pi, pi, pi, pi);
  9. std::cout << std::format("Default: {}, binary: {:b}, hex.: {:x}\n", 314, 314, 314);
  10. //输出为
  11. //Default: 3.1, fixed: 3.14, scientific: 3.14e+00, general: 3.1
  12. //Default: 314, binary: 100111010, hex.: 13a

自定义类型的format支持

std::formatter模板类用于针对某类型实现format打印的支持,目前C++的基本类型和大部分库类型都有相应的formatter实现。
formatter有两个成员模板函数,分别为:

  • parse:解析format属性,默认是上面的统一格式,也可以添加自己额外的属性规则
  • format:根据属性设置,修改输入的类型以达到格式化的效果

下面是一个示例:

  1. #include <format>
  2. #include <iostream>
  3. // 类型 T 的包装
  4. template<class T>
  5. struct Box {
  6. T value;
  7. };
  8. // 能用被包装值的格式说明格式化包装 Box<T>
  9. template<class T, class CharT>
  10. struct std::formatter<Box<T>, CharT> : std::formatter<T, CharT>
  11. {
  12. // 从基类继承parse(),如果不需要继承,则不需要继承父类
  13. // 通过以被包装值调用基类实现定义 format()
  14. template<class FormatContext>
  15. auto format(Box<T> t, FormatContext& fc) {
  16. return std::formatter<T, CharT>::format(t.value, fc);
  17. }
  18. };
  19. int main()
  20. {
  21. Box<int> v = { 42 };
  22. std::cout << std::format("{:#x}", v);
  23. }