首页 > 编程语言 >C++ fmt

C++ fmt

时间:2024-08-07 15:49:32浏览次数:12  
标签:std chrono fmt format C++ print spec

Input/output library

cppreference Input/output library

有三种 io 库:

  • OOP 样式,基于流的 io
  • 基于 print 的系列函数
  • C 样式的 IO 函数

基于流的 'io' 库

基于流的 'io' 库是围绕抽象的 io 设备来进行组织的,这些抽象的设备允许使用相同的代码处理输入/输出文件,内存流,或定制的适配器设备,其动态执行任意操作(例如压缩)。

ios_base
	basic_ios
		basic_ostream
			basic_ostringstream
			basic_ofstream
		basic_istream
			basic_istringstream
			basic_ifstream

			basic_iostream
				basic_stringstream
				basic_fstream

ios_base

ios_base
	state info
	control info
	它可以实现为两个任意长度的数组,或者一个由两个元素组成的数组结构体或另一个容器。
	callbacks

flag
	precison
	width
	formatting

exception mask
buffer error state

imbued locale

xalloc()

dec, oct, hex, basefield, left, right, internal, adjustfield, scientific, fixed, floatfield, boolalpha, showbase, showpoint, showpos, skipws, unitbuf, uppercase

在控制台乱码的情况

在源文件中设置 locale 能不能解决控制台的乱码情况?

#include <iostream>
#include <locale>

int main(int argc, char *argv[]) {
    std::setlocale(LC_ALL, "");
    std::cout << "你是你世界的主角,戏份由你安排!" << '\n';
    return 0;
}    

编译: g++ .\setlocale.cpp -o jkl

$ chcp 437
Active code page: 437
$ .\jkl.exe
����~_����,-�O�s,�,��'��O�^?����"���r%�Z'��?

编译: g++ .\setlocale.cpp -finput-charset=utf-8 -o jkl

$ chcp 437
Active code page: 437
$ .\jkl.exe
����~_����,-�O�s,�,��'��O�^?����"���r%�Z'��?
$ chcp 65001
Active code page: 65001
$ .\jkl.exe
ä

setlocale(LC_ALL, "en_US.UTF-8");

#include <iostream>
#include <locale>

int main(int argc, char *argv[]) {
    //std::setlocale(LC_ALL, "");
    std::setlocale(LC_ALL, "en_US.UTF_8");
    std::cout << "你是你世界的主角,戏份由你安排!" << '\n';
    return 0;
}

编译:g++ .\setlocale.cpp -o kkp

$ chcp 437
Active code page: 437
$ .\kkp.exe
你是你世界的主角,戏份由你安排!

用编译器的 utf8 选项来编译,能不能在 chcp 437 的控制台上正确的显示中文?

#include <iostream>

int main() {
	std::cout << "你是最棒的!" << std::endl;
}

编译: g++ .\compile-use-utf8.cpp -finput-charset=utf-8 -o jkl

$ chcp 437
Active code page: 437
$ .\jkl.exe
你是最棒的!

fmt

fmt 是一个开源的,格式化库,它是快速、安全的,可以替代 C stdioC++ iostreams

特征:

  • 简单的 api
  • C++20 std::formatC++23 std::print 的实现
  • 类似于 python 格式化语法
  • IEEE 754 的快述圆整,使用Dragonbox算法保证短途和往返
  • 可移植的 unicode 支持
  • 安全的 printf 实现,包含 POSIX 对位置参数的扩展
  • 可扩展:支持用户自定义类型
  • 高性能:比 (s)printf, iostream, to_stringto_chars
  • 在源代码方面代码量小,最小配置仅由三个文件组成:core.h, format.hformat-inl.h
  • 可靠性:该库有一套广泛的测试,并且不断被模糊化
  • 安全性:该库完全类型安全,格式字符串中的错误可以在编译时报告,自动内存管理可防止缓冲区溢出错误
  • 易用性:小型自包含代码库,无外部依赖,宽松的MIT许可证
  • 可移植性,跨平台输出一致,支持旧编译器
  • 即使在高警告级别(如-Wall-Wextra-pedantic)上,也要清理无警告的代码库
  • 默认情况下独立于区域设置
  • 使用FMT_header_only宏启用可选的仅标头配置

使用第一个参数打印,使用 s 的指定类型为 stringstring 的打印需要手动指定类型,而 int 等不需要) ,中间对齐 ^,两侧填充 -,宽度为 30

(具体的格式化标记见:https://fmt.dev/11.0/)

#define FMT_HEADER_ONLY 1
#include <fmt/format.h>
#include <string>

int main() {
    fmt::print("{0:-^30s}\n", std::string("center"));
}

fmt 的组件

  • fmt/base.h:基本的 API 提供主要的格式化函数
  • fmt/format.hfmt::format 和其他的格式化函数,以及 locale 支持
  • fmt/ranges.h: 对 rangestuple 进行格式化
  • fmt/chrono.h: 日期和时间的格式化
  • fmt/std.h:用于标准库类型的格式器
  • fmt/compile.h:格式字符串编译
  • fmt/color.h:终端的色彩和文本样式
  • fmt/os.h:系统 APIs
  • fmt/ostream.hstd::ostream支持
  • fmt/args.h:动态参数列表
  • fmt/printf.hprintf格式化
  • fmt/xchar.h:可选的 wchar_t 支持

fmt 库中提供的类型和函数都在命名空间 fmt 中,然后库的所有宏都有前缀 FMT_

cmake 中使用

FetchContent: 从 cmake 3.11 开始,使用 FetchContent自动下载fmt` 作为配置时的依赖项:

include(FetchContent)

FetchContent_Declare(
  fmt
  GIT_REPOSITORY https://github.com/fmtlib/fmt
  GIT_TAG        e69e5f977d458f2650bb346dadf2ad30c5320281) # 10.2.1
FetchContent_MakeAvailable(fmt)

target_link_libraries(<your-target> fmt::fmt)

已安装:找到已安装 fmt ,然后在你的 CMakeLists.txt 中使用:

find_package(fmt)
target_link_libraries(<your-target> fmt::fmt)

直接嵌入: 直接使用源码树在你的项目中,在你的 CMakeLists.txt 中使用:

add_subdirectory(fmt)
target_link_libraries(<your-target> fmt::fmt)

Header-only 的方式使用

https://github.com/fmtlib/fmt/issues/524

You don't need CMake for that, just define FMT_HEADER_ONLY macro to 1 when including fmt/format.h.

replacement-field 替换字段的使用和它的格式化

replacement_field ::= "{" [arg_id] [":" (format_spec | chrono_format_spec)] "}"
arg_id            ::= integer | identifier
integer           ::= digit+
digit             ::= "0"..."9"
identifier        ::= id_start id_continue*
id_start          ::= "a"..."z" | "A"..."Z" | "_"
id_continue       ::= id_start | digit

format_spec 可以是,字段宽,对齐,填充,数字精度等。format_spec可以包含嵌套的替换字段在其中确切的位置。

format_spec ::= [[fill]align][sign]["#"]["0"][width]["." precision]["L"][type]
fill        ::= <a character other than '{' or '}'>
align       ::= "<" | ">" | "^"
sign        ::= "+" | "-" | " "
width       ::= integer | "{" [arg_id] "}"
precision   ::= integer | "{" [arg_id] "}"
type        ::= "a" | "A" | "b" | "B" | "c" | "d" | "e" | "E" | "f" | "F" |
                "g" | "G" | "o" | "p" | "s" | "x" | "X" | "?"

chrono_format_spec

chrono_format_spec ::= [[fill]align][width]["." precision][chrono_specs]
chrono_specs       ::= conversion_spec |
                       chrono_specs (conversion_spec | literal_char)
conversion_spec    ::= "%" [padding_modifier] [locale_modifier] chrono_type
literal_char       ::= <a character other than '{', '}' or '%'>
padding_modifier   ::= "-" | "_"  | "0"
locale_modifier    ::= "E" | "O"
chrono_type        ::= "a" | "A" | "b" | "B" | "c" | "C" | "d" | "D" | "e" |
                       "F" | "g" | "G" | "h" | "H" | "I" | "j" | "m" | "M" |
                       "n" | "p" | "q" | "Q" | "r" | "R" | "S" | "t" | "T" |
                       "u" | "U" | "V" | "w" | "W" | "x" | "X" | "y" | "Y" |
                       "z" | "Z" | "%"

打印指针

Chrono Format Specifications

chrono_format_spec ::= [[fill]align][width]["." precision][chrono_specs]
chrono_specs       ::= conversion_spec |
                       chrono_specs (conversion_spec | literal_char)
conversion_spec    ::= "%" [padding_modifier] [locale_modifier] chrono_type
literal_char       ::= <a character other than '{', '}' or '%'>
padding_modifier   ::= "-" | "_"  | "0"
locale_modifier    ::= "E" | "O"
chrono_type        ::= "a" | "A" | "b" | "B" | "c" | "C" | "d" | "D" | "e" |
                       "F" | "g" | "G" | "h" | "H" | "I" | "j" | "m" | "M" |
                       "n" | "p" | "q" | "Q" | "r" | "R" | "S" | "t" | "T" |
                       "u" | "U" | "V" | "w" | "W" | "x" | "X" | "y" | "Y" |
                       "z" | "Z" | "%"

Range Format Specifications

范围类型的格式规范具有以下语法:

range_format_spec ::= ["n"][range_type][range_underlying_spec]
fmt::print("{}", std::vector{10, 20, 30});
// Output: [10, 20, 30]
fmt::print("{::#x}", std::vector{10, 20, 30});
// Output: [0xa, 0x14, 0x1e]
fmt::print("{}", std::vector{'h', 'e', 'l', 'l', 'o'});
// Output: ['h', 'e', 'l', 'l', 'o']
fmt::print("{:n}", std::vector{'h', 'e', 'l', 'l', 'o'});
// Output: 'h', 'e', 'l', 'l', 'o'
fmt::print("{:s}", std::vector{'h', 'e', 'l', 'l', 'o'});
// Output: "hello"
fmt::print("{:?s}", std::vector{'h', 'e', 'l', 'l', 'o', '\n'});
// Output: "hello\n"
fmt::print("{::}", std::vector{'h', 'e', 'l', 'l', 'o'});
// Output: [h, e, l, l, o]
fmt::print("{::d}", std::vector{'h', 'e', 'l', 'l', 'o'});
// Output: [104, 101, 108, 108, 111]

print

template <typename... T>
void print(FILE* f, format_string<T...> fmt, T&&... args);

FILE

FILE | cppreference

stream state

除了系统指定的,访问设备所必需的信息外(也就是 POSIX 文件描述符),每 FILE 对象都直接或间接的持有以下的信息:

  • 字符宽度:unset, narror, or wide.
  • 用于在多字节和宽字符间转换时(mbstate_t 对象的类型),的解析状态。
  • 缓冲状态:unbuffered, line-buffered, fully buffered。
  • 一个缓冲,可能被外部的、用户提供的缓冲所替代。
  • I/O 模式: input, output 和 update(input 和 output)。
  • Binary/text 模式说明符。
  • End-of-file 状态说明符。
  • 文件位置说明符,一个可访问的对象,有着 fpos_t 类型,对于 wide streams ,包含解析状。
  • 可重入的锁,用于在多线程读、写、定位或查询流的位置时,防止数据竞争。

Narrow 和 wide 的面向

新打开的流没有方向。对fwide或任何I/O函数的第一次调用建立了定向:<详情见原文>

窄向,宽向

二进制模式和文本模式

文本流是一个有序的字符序列,能组合进一行中;'\n' 文本流中表示一行。最后一行是否需要由 '\n' 终结是实现定义的。此外,可能需要在输入和输出时添加、修改或删除字符,以符合操作系统中表示文本的约定(特别是,Windows操作系统上的C流在输出时将'\n'转换为'\r\n',并在输入时将'\r\n'转换为'\n')。

读取的数据可以等同于写入的数据,只要以下的条件为真:

  • 数据的构成由唯一的可打印的字和/或唯一的控制字符 '\t''\n'(实践中,在 windows 系统,`'\0x1A' 会终结输入)。
  • 没有空格字符紧接在'\n'字符前面(这些空格字符可能在以后将输出作为输入读取时消失)。
  • 最后的字符是 '\n'

二进制流是一个有序的字符序列,可以透明地记录内部数据。从二进制流读入的数据总是等于先前写入该流的数据,除了允许在流的末尾附加不确定数量的空字符。宽二进制流不需要在初始移位状态中结束。

stdin, stdout, stderr

stdin expression of type FILE* associated with the input stream

stdout expression of type FILE* associated with the output stream

stderr expression of type FILE* associated with the error output stream

unsigned int fread(void *buffer, unsigned int size, unsigned int count, FILE *fp);
unsigned int fwrite(const void* buffer, unsigned int size, unsigned int count, FILE *fp);

buffer 指向的内存中的数据块写入 fp 所指的文件,buffer k待输出数据块的起始地址,size 是每个数据块的大小(字节数),count 是最多允许写入的数据块的个数(每个数据块是 size 个字节),函数返回的是实际写入的数据块的个数。

fread()函数和 fwrite()函数是按数据块的长度来处理输入/输出的,在用文本编辑器打开文本文件时可能因发生字符转换而出现莫名其妙的结果,所以这两个函数通常用于二进制文件的输入/输出

标签:std,chrono,fmt,format,C++,print,spec
From: https://www.cnblogs.com/lin-hui/p/18347179

相关文章

  • 利用异或解决“只出现一次的数字“问题的C++解决方案
    该问题的输入是一个整数数组nums,其中除了一个数字之外,其余数字都出现了两次。任务是找到那个只出现一次的数字,并将其返回。 classSolution{public:  intsingleNumber(vector<int>&nums){    intval=0;    for(size_ti=0;i<nums.size();i++......
  • 【C/C++】 现有n个正整款,n<10000,要求出这n个正整数中的第k个最小整数(相同大小的整数
    现有n个正整款,n<10000,要求出这n个正整数中的第k个最小整数(相同大小的整数只计算一次)k≤1000,正整数均小于30000.第一行输入n和k,第二行输入有n个正整数的数组(有重复的数字)#include<iostream>#include<algorithm>usingnamespacestd;intmain(){intn=0,k=0;......
  • vscode C++ 自动补全失效
    设置搜索这几个,并设置为对应值。 如果没解决,可能是clangd的问题。禁用clangd,然后去看看c_cpp_properties.json。看complierPath是不是clang。如果是,改成g++/gcc。再看一下intelliSenseMode是不是clang。如果是,改为default。 linux下c_cpp_properties.json的配置 ......
  • 【数据结构与算法】删除循环队列中第k个元素的算法 C++实现(循环队列+模运算)
    数组a[MaxSize]用作一个循环队列,front指向循环队列中队头元素的前一个位置,rear指向队尾元素的位置。设计删除队列中第k个元素的算法。思路首先,判断kkk是否在有效范围内......
  • 【数据结构与算法】在循环队列中第k个元素之后插入元素的算法 C++实现(循环队列+模运算
    数组a[MaxSize]用作一个循环队列,front指向循环队列中队头元素的前一个位置,rear指向队尾元素的位置。设计在队列中第k个元素之后插入item的算法。思路首先,检查输入的位置k是否在合理的范围内,即1到queueSize(Q)(包含两端)。如果k在这个范围外,那么返回ERROR。然后,计......
  • 【NOI】C++算法设计入门之穷举
    文章目录前言一、概念1.导入2.概念二、例题讲解1.简单穷举问题:1015.鸡兔同笼问题问题:1351.买公园门票问题:1016.买小猫小狗问题:1220.买糕点问题:1396.开学大采购?2.嵌套穷举问题:1022.百钱百鸡问题问题:1024.购买文具问题:1249.搬砖问题问题:1250.马克思手稿的问题......
  • 学懂C++(七): C++错误处理机制 -- 异常
    目录前言一、C语言传统的处理错误的方式二、C++异常的概念三、异常的使用3.1异常的抛出和匹配原则3.2在函数调用链中异常栈展开匹配原则3.3异常的重新抛出3.4异常规范四、自定义异常体系五、异常的优缺点优点缺点结论前言        C++提供了一......
  • 【C++从小白到大牛】多态那些事儿(上)
    目录一、多态的概念1.1概念:二、多态的定义及实现 2.1多态的构成条件在继承中要多态还要两个条件 2.2虚函数2.3虚函数的重写2.4虚函数重写的两个例外:1.协变(基类与派生类虚函数返回值类型不同)(了解不重要)2.析构函数的重写(基类与派生类析构函数的名字不同)2......
  • C++入门基础1
    目录1.c++发展历史2.C++在⼯作领域中的应⽤3.C++学习建议和书籍推荐3.1学习难度3.2书籍的推荐4.c++第一个程序5.命名空间5.1namesapce的价值5.2namespace的定义5.2.1 正常的命名空间定义5.3命名空间的使用5.3.1指定命名空间访问5.3.2using将命名空间中某......
  • C++笔记,类和对象(上)
    对于类的初步认识目录对于类的初步认识(1)类的定义(2)类的访问限定符及封装(3)类的作用域(4)类的实例化(5)类的对象大小的计算(6)类成员函数的this指针(1)类的定义classclassName{//类体,由成员函数和成员变量组成};//一定要注意后面的分号类体中内容称为类的成员:类......