{fmt} คือไลบรารีการจัดรูปแบบโอเพ่นซอร์สซึ่งเป็นทางเลือกที่รวดเร็วและปลอดภัยสำหรับ C stdio และ C++ iostreams
หากคุณชอบโครงการนี้ โปรดพิจารณาบริจาคเงินให้กับหนึ่งในกองทุนที่ช่วยเหลือผู้ประสบภัยสงครามในยูเครน: https://www.stopputin.net/
เอกสารประกอบ
แผ่นโกง
ถาม&ตอบ: ถามคำถามเกี่ยวกับ StackOverflow ด้วยแท็ก fmt
ลองใช้ {fmt} ใน Compiler Explorer
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
ดูเอกสารประกอบสำหรับรายละเอียดเพิ่มเติม
พิมพ์ไปที่ stdout (รัน)
#include <fmt/core.h>int main() { fmt::print("สวัสดีชาวโลก!n"); -
จัดรูปแบบสตริง (รัน)
std::string s = fmt::format("คำตอบคือ {}.", 42);// s == "คำตอบคือ 42"
จัดรูปแบบสตริงโดยใช้อาร์กิวเมนต์ตำแหน่ง (รัน)
std::string s = fmt::format("ฉันอยากจะเป็น {1} มากกว่า {0}.", "ใช่", "มีความสุข");// s == "ฉันอยากจะมีความสุขมากกว่าถูก ”
พิมพ์วันที่และเวลา (รัน)
#include <fmt/chrono.h>int main() { อัตโนมัติตอนนี้ = 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 <vector>#include <fmt/ranges.h>int main() { มาตรฐาน::เวกเตอร์<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() { ออกอัตโนมัติ = 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", "world" ); 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:
ห้องสมุด | วิธี | รันไทม์, ส |
---|---|---|
libc | พิมพ์ฉ | 0.91 |
libc++ | มาตรฐาน::ostream | 2.49 |
{fmt} 9.1 | fmt::พิมพ์ | 0.74 |
บูสต์รูปแบบ 1.80 | เพิ่ม :: รูปแบบ | 6.26 |
รูปแบบความโง่เขลา | ความโง่เขลา::รูปแบบ | 1.87 |
{fmt} เป็นวิธีที่เร็วที่สุดในการวัดประสิทธิภาพ ซึ่งเร็วกว่า printf
ประมาณ 20%
ผลลัพธ์ข้างต้นสร้างขึ้นโดยการสร้าง tinyformat_test.cpp
บน macOS 12.6.1 ด้วย clang++ -O3 -DNDEBUG -DSPEED_TEST -DHAVE_FORMAT
และดำเนินการรันให้ดีที่สุดจากสามรัน ในการทดสอบ สตริงรูปแบบ "%0.10f:%04d:%+g:%s:%p:%c:%%n"
หรือเทียบเท่าจะถูกเติม 2,000,000 ครั้งโดยส่งออกเอาต์พุตไปที่ /dev/null
; สำหรับรายละเอียดเพิ่มเติมอ้างอิงถึงแหล่งที่มา
{fmt} เร็วกว่า std::ostringstream
และ sprintf
ถึง 20-30 เท่าบน IEEE754 float
และการจัดรูป double
(dtoa-benchmark) และเร็วกว่า double-conversion และ ryu:
สคริปต์ bloat-test.py จากการทดสอบ format-benchmark เวลาในการคอมไพล์และโค้ดขยายสำหรับโครงการที่ไม่สำคัญ สร้างหน่วยการแปล 100 หน่วยและใช้ printf()
หรือทางเลือกอื่น 5 ครั้งในแต่ละหน่วยเพื่อจำลองโครงการขนาดกลาง ขนาดปฏิบัติการและเวลาคอมไพล์ที่ได้ (Apple clang เวอร์ชัน 15.0.0 (clang-1500.1.0.2.5), macOS Sonoma ดีที่สุดในสาม) จะแสดงอยู่ในตารางต่อไปนี้
โครงสร้างที่ปรับให้เหมาะสม (-O3)
วิธี | เวลาคอมไพล์, s | ขนาดปฏิบัติการ KiB | ขนาดถอดได้ KiB |
---|---|---|---|
พิมพ์ฉ | 1.6 | 54 | 50 |
IOStreams | 25.9 | 98 | 84 |
fmt 83652df | 4.8 | 54 | 50 |
รูปแบบจิ๋ว | 29.1 | 161 | 136 |
รูปแบบบูสต์ | 55.0 | 530 | 317 |
{fmt} คอมไพล์ได้รวดเร็วและเทียบได้กับ printf
ในแง่ของขนาดไบนารี่ต่อการโทร (ภายในข้อผิดพลาดในการปัดเศษบนระบบนี้)
โครงสร้างที่ไม่ได้รับการปรับให้เหมาะสม
วิธี | เวลาคอมไพล์, s | ขนาดปฏิบัติการ KiB | ขนาดถอดได้ KiB |
---|---|---|---|
พิมพ์ฉ | 1.4 | 54 | 50 |
IOStreams | 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 เป็นไลบรารี่แบบส่วนหัวเท่านั้น ดังนั้นจึงไม่มีตัวเลือกการเชื่อมโยงใดๆ
โปรดดูการสร้างไลบรารีสำหรับคำแนะนำเกี่ยวกับวิธีการสร้างไลบรารีและรันการทดสอบหน่วย
เกณฑ์มาตรฐานอยู่ในพื้นที่เก็บข้อมูลแยกต่างหาก ซึ่งก็คือรูปแบบเกณฑ์มาตรฐาน ดังนั้นในการเรียกใช้เกณฑ์มาตรฐาน คุณจะต้องโคลนพื้นที่เก็บข้อมูลนี้และสร้าง Makefiles ด้วย CMake ก่อน:
$ 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: ไลบรารีโอเพ่นซอร์สสำหรับการเขียนโปรแกรมทางคณิตศาสตร์
FoundationDB ของ Apple: ที่เก็บคีย์-ค่าแบบโอเพ่นซอร์สแบบกระจายและทำธุรกรรม
Aseprite: เครื่องมือแก้ไขภาพต่อเรียงแบบเคลื่อนไหวและภาพพิกเซล
AvioBook: ชุดปฏิบัติการเครื่องบินที่ครอบคลุม
Blizzard Battle.net: แพลตฟอร์มเกมออนไลน์
Celestia: การแสดงภาพอวกาศ 3 มิติแบบเรียลไทม์
Ceph: ระบบจัดเก็บข้อมูลแบบกระจายที่ปรับขนาดได้
ccache: แคชคอมไพเลอร์
ClickHouse: ระบบจัดการฐานข้อมูลเชิงวิเคราะห์
ContextVision: ซอฟต์แวร์สร้างภาพทางการแพทย์
Contour: โปรแกรมจำลองเทอร์มินัลที่ทันสมัย
CUAUV: ยานพาหนะใต้น้ำอัตโนมัติของ Cornell University
Drake: กล่องเครื่องมือการวางแผน การควบคุม และการวิเคราะห์สำหรับระบบไดนามิกแบบไม่เชิงเส้น (MIT)
ผู้แทน: พร็อกซี C++ L7 และบัสการสื่อสาร (Lyft)
FiveM: เฟรมเวิร์กการดัดแปลงสำหรับ GTA V
fmtlog: ไลบรารีการบันทึกสไตล์ fmtlib ที่มีประสิทธิภาพพร้อมเวลาแฝงในหน่วยนาโนวินาที
ความโง่เขลา: ห้องสมุดโอเพ่นซอร์สของ Facebook
GemRB: การใช้งานโอเพ่นซอร์สแบบพกพาของ Infinity Engine ของ Bioware
Grand Mountain Adventure: เกมสกีและสโนว์บอร์ดแบบเปิดโลกที่สวยงาม
HarpyWar/pvpgn: Player vs Player Gaming Network พร้อมการปรับแต่ง
KBEngine: เอ็นจิ้นเซิร์ฟเวอร์ MMOG โอเพ่นซอร์ส
Keypirinha: ตัวเรียกความหมายสำหรับ Windows
Kodi (เดิมคือ xbmc): ซอฟต์แวร์โฮมเธียเตอร์
Knuth: Bitcoin โหนดเต็มประสิทธิภาพสูง
libunicode: ไลบรารี Unicode C++17 ที่ทันสมัย
MariaDB: ระบบจัดการฐานข้อมูลเชิงสัมพันธ์
Microsoft Verona: วิจัยภาษาการเขียนโปรแกรมเพื่อการเป็นเจ้าของพร้อมกัน
MongoDB: ฐานข้อมูลเอกสารแบบกระจาย
MongoDB Smasher: เครื่องมือขนาดเล็กสำหรับสร้างชุดข้อมูลแบบสุ่ม
OpenSpace: กรอบงานดาราศาสตร์แบบโอเพ่นซอร์ส
PenUltima Online (POL): เซิร์ฟเวอร์ MMO ที่เข้ากันได้กับไคลเอนต์ Ultima Online ส่วนใหญ่
PyTorch: ไลบรารีการเรียนรู้ของเครื่องแบบโอเพ่นซอร์ส
quasardb: ฐานข้อมูลแบบกระจายที่มีประสิทธิภาพสูงและเชื่อมโยง
Quill: ไลบรารีการบันทึกเวลาแฝงต่ำแบบอะซิงโครนัส
QKW: การกำหนดนามแฝงทั่วไปเพื่อทำให้การนำทางง่ายขึ้น และดำเนินการลำดับคำสั่งเทอร์มินัลหลายบรรทัดที่ซับซ้อน
redis-cerberus: พร็อกซีคลัสเตอร์ Redis
redpanda: การแทนที่ Kafka® ที่เร็วขึ้น 10 เท่าสำหรับระบบภารกิจสำคัญที่เขียนด้วยภาษา C++
rpclib: เซิร์ฟเวอร์ C++ msgpack-RPC ที่ทันสมัยและไลบรารีไคลเอนต์
Salesforce Analytics Cloud: ซอฟต์แวร์ระบบธุรกิจอัจฉริยะ
Scylla: ที่เก็บข้อมูล NoSQL ที่เข้ากันได้กับ Cassandra ซึ่งสามารถจัดการธุรกรรม 1 ล้านรายการต่อวินาทีบนเซิร์ฟเวอร์เดียว
Seastar: เฟรมเวิร์ก C++ โอเพ่นซอร์สขั้นสูงสำหรับแอปพลิเคชันเซิร์ฟเวอร์ประสิทธิภาพสูงบนฮาร์ดแวร์สมัยใหม่
spdlog: ไลบรารีการบันทึก C ++ ที่เร็วสุด ๆ
Stellar: แพลตฟอร์มทางการเงิน
การผ่าตัดแบบสัมผัส: จำลองการผ่าตัด
TrinityCore: เฟรมเวิร์ก MMORPG โอเพ่นซอร์ส
- เฟรมเวิร์กผู้ใช้: เฟรมเวิร์กอะซิงโครนัสแบบโอเพ่นซอร์สพร้อมชุดนามธรรมและไดรเวอร์ฐานข้อมูลที่หลากหลาย
เทอร์มินัล Windows: เทอร์มินัล Windows ใหม่
มากกว่า...
หากคุณทราบถึงโครงการอื่นๆ ที่ใช้ห้องสมุดนี้ โปรดแจ้งให้เราทราบทางอีเมลหรือส่งปัญหา
เหตุใดจึงต้องมีไลบรารีการจัดรูปแบบอื่นอีก
มีวิธีการมากมายในการทำงานนี้ ตั้งแต่วิธีมาตรฐาน เช่น ฟังก์ชันตระกูล printf และ iostreams ไปจนถึงไลบรารี Boost Format และ FastFormat เหตุผลในการสร้างไลบรารีใหม่ก็คือโซลูชันที่มีอยู่ทุกโซลูชันที่ฉันพบนั้นมีปัญหาร้ายแรงหรือไม่ได้ให้คุณสมบัติทั้งหมดที่ฉันต้องการ
ข้อดีของ printf
ก็คือมันค่อนข้างเร็วและพร้อมใช้งานโดยเป็นส่วนหนึ่งของไลบรารี่มาตรฐาน C ข้อเสียเปรียบหลักคือไม่รองรับประเภทที่ผู้ใช้กำหนด printf
ยังมีปัญหาด้านความปลอดภัยแม้ว่าจะบรรเทาลงบ้างด้วย __attribute__ ((รูปแบบ (printf, ...)) ใน GCC มีส่วนขยาย POSIX ที่เพิ่มอาร์กิวเมนต์ตำแหน่งที่จำเป็นสำหรับ i18n เพื่อ printf
แต่ไม่ได้เป็นส่วนหนึ่งของ C99 และอาจ ไม่สามารถใช้ได้ในบางแพลตฟอร์ม
ปัญหาหลักของ iostreams แสดงให้เห็นได้ดีที่สุดด้วยตัวอย่าง:
std::cout << std::setprecision(2) << std::fixed << 1.23456 << "n";
ซึ่งมีการพิมพ์จำนวนมากเมื่อเทียบกับ printf:
printf("%.2fn", 1.23456);
แมทธิว วิลสัน ผู้เขียน FastFormat เรียกสิ่งนี้ว่า "บั้งนรก" iostreams ไม่รองรับข้อโต้แย้งเกี่ยวกับตำแหน่งตามการออกแบบ
ส่วนที่ดีก็คือ iostreams รองรับประเภทที่ผู้ใช้กำหนดและปลอดภัย แม้ว่าการจัดการข้อผิดพลาดจะไม่สะดวกก็ตาม
นี่เป็นไลบรารีที่ทรงพลังมากซึ่งรองรับทั้งสตริงรูปแบบที่เหมือน printf
และอาร์กิวเมนต์ตำแหน่ง ข้อเสียเปรียบหลักคือประสิทธิภาพ จากเกณฑ์มาตรฐานต่างๆ พบว่าวิธีนี้ช้ากว่าวิธีอื่นๆ ที่พิจารณาในที่นี้มาก Boost Format ยังมีเวลาในการสร้างมากเกินไปและปัญหาการขยายโค้ดที่รุนแรง (ดูเกณฑ์มาตรฐาน)
นี่เป็นห้องสมุดที่น่าสนใจรวดเร็ว ปลอดภัย และมีข้อโต้แย้งเกี่ยวกับตำแหน่ง อย่างไรก็ตาม มีข้อจำกัดที่สำคัญ โดยอ้างผู้เขียน:
คุณสมบัติสามประการที่ไม่หวังว่าจะได้รับการรองรับภายในการออกแบบปัจจุบันคือ:
ศูนย์นำหน้า (หรือช่องว่างภายในอื่นๆ ที่ไม่เว้นวรรค)
การเข้ารหัสฐานแปด/เลขฐานสิบหก
ข้อกำหนดความกว้าง/การจัดตำแหน่งรันไทม์
นอกจากนี้ยังมีขนาดค่อนข้างใหญ่และมีการพึ่งพาอย่างมากใน STLSoft ซึ่งอาจจำกัดเกินไปสำหรับการใช้ในบางโครงการ
นี่ไม่ใช่ไลบรารีการจัดรูปแบบ แต่ฉันตัดสินใจรวมไว้ที่นี่เพื่อความสมบูรณ์ ในฐานะที่เป็น iostreams มันประสบปัญหาในการผสมข้อความคำต่อคำกับข้อโต้แย้ง ไลบรารีค่อนข้างเร็ว แต่ช้ากว่าในการจัดรูปแบบจำนวนเต็มมากกว่า fmt::format_to
พร้อมการรวบรวมสตริงรูปแบบบนเกณฑ์มาตรฐานของ Karma ดูที่การแปลงจำนวนเต็มร้อยล้านเป็นสตริงต่อวินาที
{fmt} ได้รับการเผยแพร่ภายใต้ใบอนุญาต MIT
ส่วนไวยากรณ์สตริงรูปแบบในเอกสารประกอบจะขึ้นอยู่กับส่วนจากเอกสารประกอบโมดูลสตริง Python ด้วยเหตุนี้ เอกสารประกอบจึงเผยแพร่ภายใต้ลิขสิทธิ์ Python Software Foundation ซึ่งมีอยู่ใน doc/python-license.txt ใช้ได้เฉพาะเมื่อคุณแจกจ่ายเอกสารของ {fmt}
ห้องสมุด {fmt} ได้รับการดูแลโดย Victor Zverovich (vitaut) โดยได้รับความช่วยเหลือจากคนอื่นๆ มากมาย ดูผู้มีส่วนร่วมและการเผยแพร่สำหรับชื่อบางส่วน แจ้งให้เราทราบหากการมีส่วนร่วมของคุณไม่อยู่ในรายการหรือกล่าวถึงอย่างไม่ถูกต้อง แล้วเราจะดำเนินการให้ถูกต้อง
หากต้องการรายงานปัญหาด้านความปลอดภัย โปรดเปิดเผยที่ที่ปรึกษาด้านความปลอดภัย
โครงการนี้ได้รับการดูแลโดยทีมอาสาสมัครบนพื้นฐานความพยายามที่สมเหตุสมผล ด้วยเหตุนี้ โปรดให้เวลาเราอย่างน้อย 90 วันในการดำเนินการแก้ไขก่อนที่จะเผยแพร่สู่สาธารณะ