{fmt}是一個開源格式化函式庫,為 C stdio 和 C++ iostream 提供快速、安全的替代方案。
如果您喜歡這個項目,請考慮向幫助烏克蘭戰爭受害者的基金之一捐款:https://www.stopputin.net/。
文件
備忘錄
Q&A:使用標籤 fmt 在 StackOverflow 上提問。
在編譯器資源管理器中嘗試 {fmt}。
具有用於本地化的位置參數的簡單格式 API
C++20 std::format 和 C++23 std::print 的實現
格式化字串語法類似於Python的格式
快速 IEEE 754 浮點格式化程序,使用 Dragonbox 演算法提供正確的捨去、縮短和往返保證
便攜式 Unicode 支援
安全 printf 實現,包括位置參數的 POSIX 擴展
可擴展性:支援使用者定義類型
高效能:比(s)printf
、 iostreams 、 to_string
和to_chars
的常見標準函式庫實作更快,請參閱速度測試和每秒將一億個整數轉換為字串
程式碼量小,原始碼最小配置僅包含三個檔案: core.h
、 format.h
和format-inl.h
,以及編譯後的程式碼;請參閱編譯時間和程式碼膨脹
可靠性:該庫進行了廣泛的測試,並且不斷進行模糊測試
安全性:該庫是完全類型安全的,可以在編譯時報告格式字串中的錯誤,自動記憶體管理可防止緩衝區溢位錯誤
易於使用:小型獨立程式碼庫,無外部依賴項,寬鬆的 MIT 許可證
具有跨平台一致輸出的可攜性以及對舊版編譯器的支持
即使在高警告等級(例如-Wall -Wextra -pedantic
下,也乾淨且無警告的程式碼庫
預設與語言環境無關
使用FMT_HEADER_ONLY
巨集啟用可選的僅標頭配置
請參閱文件以了解更多詳細資訊。
列印到標準輸出(運行)
#include <fmt/core.h>int main() { fmt::print("你好,世界!n"); }
格式化字串(運行)
std::string s = fmt::format("答案是 {}.", 42);// s == "答案是 42."
使用位置參數格式化字串(運行)
std::string s = fmt::format("我寧願成為 {1} 而不是 {0}。", "right", "happy");// s == "我寧願成為快樂而不是 right 」。
列印日期和時間(運行)
#include <fmt/chrono.h>int main() { auto now = std::chrono::system_clock::now(); fmt::print("日期和時間:{}n",現在); fmt::print("時間: {:%H:%M}n", 現在); }
輸出:
Date and time: 2023-12-26 19:10:31.557195597 Time: 19:10
列印容器(運行)
#include <向量>#include <fmt/ranges.h>int main() { std::vector<int> v = {1, 2, 3}; fmt::print("{}n", v); }
輸出:
[1, 2, 3]
在編譯時檢查格式字串
std::string s = fmt::format("{:d}", "我不是數字");
這會在 C++20 中產生編譯時錯誤,因為d
是字串的無效格式說明符。
從單線程寫入文件
#include <fmt/os.h>int main() { auto out = fmt::output_file("guide.txt"); out.print("不要{}", "恐慌"); }
這比 fprintf 快 5 到 9 倍。
使用顏色和文字樣式進行列印
#include <fmt/color.h>int main() { fmt::print(fg(fmt::color::crimson) | fmt::emphasis::bold, "你好,{}!n", "世界" ); fmt::print(fg(fmt::color::floral_white) | bg(fmt::color::slate_gray) | fmt::emphasis::underline, "Olá, {}!n", "Mundo"); fmt::print(fg(fmt::color::steel_blue) | fmt::emphasis::italic, "你好{}!n", "世界"); }
在支援 Unicode 的現代終端機上輸出:
圖書館 | 方法 | 運轉時間,秒 |
---|---|---|
庫 | 列印函數 | 0.91 |
函式庫++ | std::ostream | 2.49 |
{fmt} 9.1 | fmt::列印 | 0.74 |
升壓格式 1.80 | 增強::格式 | 6.26 |
愚蠢的格式 | 愚蠢::格式 | 1.87 |
{fmt} 是最快的基準測試方法,比printf
快約 20%。
上述結果是透過使用clang++ -O3 -DNDEBUG -DSPEED_TEST -DHAVE_FORMAT
在 macOS 12.6.1 上建立tinyformat_test.cpp
並取三輪運行中的最佳結果產生的。在測試中,格式字串"%0.10f:%04d:%+g:%s:%p:%c:%%n"
或等效內容填入 2,000,000 次,並將輸出傳送至/dev/null
;有關更多詳細信息,請參閱來源。
在 IEEE754 float
和double
格式(dtoa-基準)上,{fmt} 比std::ostringstream
和sprintf
快 20-30 倍,並且比雙精度轉換和 ryu 更快:
format-benchmark 中的腳本 bloat-test.py 測試重要專案的編譯時間和程式碼膨脹。它產生 100 個翻譯單元,並在每個單元中使用printf()
或其替代方法五次,以模擬一個中型項目。下表顯示了產生的可執行檔大小和編譯時間(Apple clang 版本 15.0.0 (clang-1500.1.0.2.5)、macOS Sonoma,三者最佳)。
優化建置(-O3)
方法 | 編譯時間,秒 | 可執行檔大小,KiB | 剝離尺寸,KiB |
---|---|---|---|
列印函數 | 1.6 | 54 | 50 |
IO流 | 25.9 | 98 | 84 |
FMMT 83652df | 4.8 | 54 | 50 |
小格式 | 29.1 | 161 | 136 |
升壓格式 | 55.0 | 第530章 | 第317章 |
{fmt} 編譯速度很快,並且在每次呼叫的二進位大小方面與printf
相當(在該系統的捨入誤差範圍內)。
非優化構建
方法 | 編譯時間,秒 | 可執行檔大小,KiB | 剝離尺寸,KiB |
---|---|---|---|
列印函數 | 1.4 | 54 | 50 |
IO流 | 23.4 | 92 | 68 |
{fmt} 83652df | 4.4 | 89 | 85 |
小格式 | 24.5 | 204 | 161 |
升壓格式 | 36.4 | 第831章 | 第462章 |
libc
、 lib(std)c++
和libfmt
都作為共享庫鏈接,僅用於比較格式化函數開銷。 Boost Format 是一個僅包含標頭的函式庫,因此它不提供任何連結選項。
請參閱建置庫以取得有關如何建置庫和運行單元測試的說明。
基準駐留在單獨的儲存庫 format-benchmarks 中,因此要執行基準,您首先需要克隆此儲存庫並使用 CMake 產生 Makefile:
$ git clone --recursive https://github.com/fmtlib/format-benchmark.git $ cd format-benchmark $ cmake .
然後你可以運行速度測試:
$ make speed-test
或膨脹測試:
$ make bloat-test
clang-tidy v18 提供了 Modernize-use-std-print 檢查,如果配置為這樣做,則能夠將printf
和fprintf
的出現轉換為fmt::print
。 (預設情況下它轉換為std::print
。)
0 AD:一款免費、開源、跨平台的即時戰略遊戲
AMPL/MP:數學規劃的開源函式庫
Apple 的 FoundationDB:開源、分散式、事務性鍵值存儲
Aseprite:動畫精靈編輯器與像素藝術工具
AvioBook:全面的飛機操作套件
Blizzard Battle.net:線上遊戲平台
Celestia:空間的即時 3D 視覺化
Ceph:可擴充的分散式儲存系統
ccache:編譯器快取
ClickHouse:分析資料庫管理系統
ContextVision:醫學影像軟體
Contour:現代終端模擬器
CUAUV:康乃爾大學的自主水下航行器
Drake:非線性動力系統的規劃、控制和分析工具箱 (MIT)
Envoy:C++ L7 代理程式與通訊匯流排 (Lyft)
FiveM:GTA V 的修改框架
fmtlog:一個高效能的 fmtlib 風格的日誌庫,延遲為奈秒級
Folly:Facebook 開源庫
GemRB:Bioware Infinity Engine 的便攜式開源實現
Grand Mountain Adventure:一款精美的開放世界滑雪和單板滑雪遊戲
HarpyWar/pvpgn:經過調整的玩家對玩家遊戲網絡
KBEngine:開源 MMOG 伺服器引擎
Keypirinha:Windows 語意啟動器
Kodi(以前的 xbmc):家庭劇院軟體
Knuth:高效能比特幣全節點
libunicode:現代 C++17 Unicode 函式庫
MariaDB:關係型資料庫管理系統
Microsoft Verona:研究並發所有權的程式語言
MongoDB:分散式文件資料庫
MongoDB Smasher:產生隨機資料集的小工具
OpenSpace:開源天文視覺化框架
PenUltima Online (POL):MMO 伺服器,與大多數 Ultima Online 用戶端相容
PyTorch:一個開源機器學習函式庫
quasardb:分散式、高效能、關聯資料庫
Quill:非同步低延遲日誌庫
QKW:通用化別名以簡化導航並執行複雜的多行終端命令序列
redis-cerberus:Redis 叢集代理
redpanda:速度提高 10 倍的 Kafka® 替代品,用於用 C++ 編寫的關鍵任務系統
rpclib:現代 C++ msgpack-RPC 伺服器和客戶端函式庫
Salesforce Analytics Cloud:商業智慧軟體
Scylla:與 Cassandra 相容的 NoSQL 資料存儲,可在單一伺服器上每秒處理 100 萬個事務
Seastar:先進的開源 C++ 框架,適用於現代硬體上的高效能伺服器應用程式
spdlog:超快速 C++ 日誌庫
Stellar:金融平台
觸控手術:手術模擬器
TrinityCore:開源 MMORPG 框架
? userver框架:開源非同步框架,具有豐富的抽象和資料庫驅動程式
Windows 終端機:新的 Windows 終端
更多的...
如果您知道使用此庫的其他項目,請透過電子郵件或提交問題讓我知道。
那為什麼還要另一個格式化函式庫呢?
有很多方法可以完成此任務,從 printf 系列函數和 iostream 等標準方法到 Boost Format 和 FastFormat 函式庫。創建新庫的原因是我發現的每個現有解決方案要么存在嚴重問題,要么沒有提供我需要的所有功能。
printf
的好處是它非常快並且作為 C 標準庫的一部分很容易使用。主要缺點是它不支援用戶定義的類型。 printf
也存在安全性問題,儘管在 GCC 中使用 __attribute__ ((format (printf, ...)) 可以在一定程度上緩解這些問題。有一個 POSIX 擴展將 i18n 所需的位置參數添加到printf
但它不是C99 的一部分,可能在某些平台上不可用。
iostreams 的主要問題最好用一個例子來說明:
std::cout << std::set precision(2) << std::fixed << 1.23456 << "n";
與 printf 相比,需要輸入大量內容:
printf("%.2fn", 1.23456);
FastFormat 的作者 Matthew Wilson 稱之為「V 形地獄」。 iostreams 在設計上不支援位置參數。
好的部分是 iostream 支援使用者定義的類型並且是安全的,儘管錯誤處理很尷尬。
這是一個非常強大的函式庫,支援類似printf
的格式字串和位置參數。它的主要缺點是性能。根據各種基準測試,它比此處考慮的其他方法慢得多。 Boost Format 還存在過多的建置時間和嚴重的程式碼膨脹問題(請參閱基準)。
這是一個有趣的函式庫,它快速、安全且具有位置參數。然而,它有很大的局限性,引用其作者的話:
目前設計中無法容納的三個功能是:
前導零(或任何其他非空格填充)
八進位/十六進位編碼
運行時寬度/對齊規範
它也相當大,並且嚴重依賴 STLSoft,這對於某些專案的使用可能過於嚴格。
這不是一個格式化庫,但為了完整性我決定將其包含在這裡。作為 iostream,它面臨著逐字文本與參數混合的問題。該函式庫相當快,但在整數格式化方面比fmt::format_to
慢,並且在 Karma 自己的基準上進行格式字串編譯,請參閱每秒將一億個整數轉換為字串。
{fmt} 是根據 MIT 許可證分發的。
文件中的格式字串語法部分是基於 Python 字串模組文件中的一節。因此,該文件根據 doc/python-license.txt 中提供的 Python Software Foundation 授權分發。它僅適用於您分發 {fmt} 文件的情況。
{fmt} 函式庫由 Victor Zverovich (vitaut) 維護,並獲得了許多其他人的貢獻。請參閱貢獻者和版本以了解其中一些名稱。如果您的貢獻未列出或提及不正確,請告訴我們,我們將予以修正。
若要通報安全問題,請在安全公告中揭露。
該計畫由一組志工在合理努力的基礎上維護。因此,在公開曝光之前,請給我們至少90天的時間進行修復。