最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++之類型安全格式化format

 更新時(shí)間:2026年06月09日 08:19:37   作者:alwaysrun  
C++20引入的std::format作為現(xiàn)代化字符串格式化工具,解決了傳統(tǒng)printf類型不安全和stringstream語(yǔ)法冗長(zhǎng)的問題,下面就來詳細(xì)的介紹一下

C++20 引入的 std::format 是基于開源 fmt 庫(kù)標(biāo)準(zhǔn)化的新式格式化接口,解決了傳統(tǒng) printf 類型不安全、stringstream 代碼冗余等問題,成為當(dāng)前 C++ 首選的格式化方案。

與 printf 和 stringstream 對(duì)比:

特性printfstringstreamstd::format
類型安全無編譯檢查,類型錯(cuò)配導(dǎo)致未定義行為 (UB)類型安全,通過 operator<< 重載編譯期檢查格式串與參數(shù)類型,錯(cuò)配即編譯報(bào)錯(cuò)
自定義對(duì)象不支持需重載 operator<<特化 std::formatter<T>,邏輯集中
格式語(yǔ)法%d/%f/%s 符號(hào)零散操控符堆砌(如 setw/hex),代碼冗長(zhǎng)統(tǒng)一 {} 占位符 + {:格式符} 語(yǔ)法
動(dòng)態(tài)寬/精度需 * 參數(shù),易用性差代碼繁瑣原生支持 {:{width}} 和 {:.{prec}} 動(dòng)態(tài)傳參
性能中等差(大量臨時(shí)對(duì)象、堆分配)優(yōu)秀(format_to 零臨時(shí)字符串)

關(guān)鍵差異:

  • printf 使用裸可變參數(shù)(C-style varargs),編譯器在編譯階段無法有效對(duì)參數(shù)類型進(jìn)行強(qiáng)校驗(yàn),極易在運(yùn)行時(shí)因類型不匹配導(dǎo)致棧破壞或未定義行為。
  • std::format 則是基于 C++ 模板變參(Variadic Templates)與編譯期常量表達(dá)式(constexpr)技術(shù),在編譯期直接解析字符串語(yǔ)法,對(duì)參數(shù)數(shù)量、參數(shù)類型進(jìn)行全方位的靜態(tài)強(qiáng)類型檢查。

核心 API

std::format

生成格式化后的字符串并返回。適用于大部分需要便捷獲取 std::string 的通用場(chǎng)景。

std::string s1 = std::format("name: {}, age: {}", "Jack", 20); // 返回 "name: Jack, age: 20"

std::format_to

高性能流式接口,直接將數(shù)據(jù)寫入指定的輸出迭代器(如 std::vector<char>、字符數(shù)組、std::ostream_iterator 等),完美避免了生成中間臨時(shí) std::string 對(duì)象的內(nèi)存分配開銷。

// 寫入字符容器(生產(chǎn)環(huán)境建議提前 reserve 以保證性能)
std::vector<char> buf;
buf.reserve(32); 
std::format_to(std::back_inserter(buf), "num = {}", 314);

// 直接零拷貝輸出到控制臺(tái)
std::format_to(std::ostream_iterator<char>(std::cout), "Hello {}\n", 666);

std::vformat

接收打包后的動(dòng)態(tài)參數(shù)包 std::format_args。該 API 主要用于封裝自定義的可變參數(shù)函數(shù),是構(gòu)建企業(yè)級(jí)通用日志系統(tǒng)或格式化包裝器的核心基石。

void log_message(std::string_view fmt, auto... args) {
    // 運(yùn)行時(shí)或編譯期將變參打包
    std::format_args pack = std::make_format_args(args...);
    // 傳遞給 vformat 執(zhí)行實(shí)際的格式化轉(zhuǎn)換
    std::cout << std::vformat(fmt, pack) << '\n';
}

int main() {
    log_message("val:{}", 123); // 輸出 "val:123"
}

占位符

通用格式:{[參數(shù)索引][:格式說明符]}

無索引{}

按照參數(shù)傳入的先后順序,從左到右依次填充。

std::format("{} + {} = {}", 1, 2, 3); // "1 + 2 = 3"

數(shù)字索引{N}

從 0 開始指定參數(shù)索引,支持顯式調(diào)換輸出順序以及同一個(gè)參數(shù)的多次復(fù)用。

std::format("{1}-{0}={1}", 5, 9); // "9-5=9"

注意: 在同一個(gè)格式化字符串中,顯式數(shù)字索引 {N} 與自動(dòng)無索引 {} 不能混用,否則會(huì)導(dǎo)致編譯期語(yǔ)法錯(cuò)誤。另外,C++ 標(biāo)準(zhǔn)庫(kù)并未原生支持如 {name} 形式的具名關(guān)鍵參數(shù)(該語(yǔ)法目前僅在開源 fmt 庫(kù)中支持)。

格式說明符

格式說明符緊跟在冒號(hào)后面,各控制分段的相對(duì)順序嚴(yán)格固定:

[填充字符][對(duì)齊][符號(hào)][#][0][寬度][.精度][類型碼]

對(duì)齊 + 填充

  • <:左對(duì)齊
  • >:右對(duì)齊(非數(shù)值默認(rèn))
  • ^:居中對(duì)齊
  • 填充字符:緊鄰對(duì)齊符號(hào)左側(cè)的任意單個(gè)字符(默認(rèn)是空格)
int n = 123;
std::format("{:*>6}", n); // "***123"
std::format("{:*<6}", n); // "123***"
std::format("{:*^6}", n); // "*123**"

符號(hào)規(guī)則(數(shù)值類型)

  • +:正數(shù)輸出 +,負(fù)數(shù)輸出 -
  • -:僅負(fù)數(shù)輸出 -(標(biāo)準(zhǔn)默認(rèn)行為)
  • (空格):正數(shù)前置補(bǔ)空格,負(fù)數(shù)輸出 -
std::format("{:+d}", 20);  // "+20"
std::format("{: d}", 20);  // " 20"
std::format("{: d}", -20); // "-20"

#進(jìn)制前綴開關(guān)

自動(dòng)為整型數(shù)據(jù)啟用前綴標(biāo)識(shí)符:十六進(jìn)制引入 0x/0X,二進(jìn)制引入 0b,八進(jìn)制引入 0

int val = 15;
std::format("{:#x}", val); // "0xf"
std::format("{:#X}", val); // "0XF"
std::format("{:#b}", val); // "0b1111"
std::format("{:#o}", val); // "017"

0前導(dǎo)補(bǔ)零

在寬度控制前加 0,空余位用字符 0 填充(本質(zhì)上等價(jià)于右對(duì)齊且用 0 填充)。

std::format("{:06d}", 123); // "000123"

最小寬度與動(dòng)態(tài)寬度

  • 固定寬度:{:6d} 表示目標(biāo)輸出至少占 6 個(gè)字符位。
  • 動(dòng)態(tài)寬度:{:{w}} 運(yùn)行時(shí)通過額外的參數(shù)動(dòng)態(tài)指定寬度。
int w = 8;
std::format("{:*>{}}", 123, w); // "*****123"

精度.prec

  • 浮點(diǎn)數(shù):指定小數(shù)點(diǎn)后的保留位數(shù)。
  • 字符串:指定最大截取字符數(shù)。
  • 動(dòng)態(tài)精度:使用 {:.{prec}} 由后續(xù)參數(shù)動(dòng)態(tài)控制。
double pi = 3.1415926;
std::format("{:.3f}", pi);    // "3.142"

std::string s = "abcdef";
std::format("{:.3}", s);      // "abc"

int prec = 2;
std::format("{:.{}}", pi, prec); // "3.14"

類型碼

不指定時(shí)將自動(dòng)根據(jù)泛型推導(dǎo)

分類標(biāo)識(shí)說明
整數(shù)d/o/x/X/b十進(jìn)制 / 八進(jìn)制 / 小寫十六進(jìn)制 / 大寫十六進(jìn)制 / 二進(jìn)制
浮點(diǎn)f/e/g/a定點(diǎn)小數(shù) / 科學(xué)計(jì)數(shù)法 / 自動(dòng)精簡(jiǎn) / 十六進(jìn)制浮點(diǎn)
布爾s/d輸出 true/false 或文本化的 1/0
指針p格式化輸出內(nèi)存物理地址
字符c將整型數(shù)值轉(zhuǎn)換為對(duì)應(yīng)的 ASCII 字符輸出
bool b = true;
std::format("{}", b);    // "true"
std::format("{:d}", b);  // "1"

自定義類型格式化

讓自定義類型支持 std::format 的核心在于顯式特化 std::formatter<T> 模板。

標(biāo)準(zhǔn)規(guī)格實(shí)現(xiàn)示例

#include <format>
#include <string>
#include <iostream>

// --- 1. 自定義數(shù)據(jù)類型 ---
struct User {
std::string name;
int age;
};

// --- 2. 在 std 命名空間內(nèi)為 User 類型特化 formatter ---
namespace std {
    // 特化版本 1: 處理 char 類型的格式字符串 (e.g., std::format)
    template <>
    struct formatter<User, char> { // 顯式指定第二個(gè)模板參數(shù)為 char
    // 必須定義 char_type,告訴格式化庫(kù)我們處理的是哪種字符
    using char_type = char;

    // 解析格式說明符的函數(shù)
    constexpr auto parse(basic_format_parse_context<char>& ctx) const {
        auto it = ctx.begin();
        auto end = ctx.end();

        // 檢查格式說明符是否為空 (即 {})
        if (it == end) {
            // 空格式說明符,解析成功,直接返回
            return it;
        }

        // 如果不為空,我們目前不支持任何格式化選項(xiàng),
        // 所以期望下一個(gè)字符必須是結(jié)束符 '}'
        if (*it != '}') {
            throw format_error("Invalid format specifier for User (char).");
        }

        // 解析成功,返回指向 '}' 的迭代器
        return it;
    }

    // 執(zhí)行實(shí)際格式化的函數(shù)
    auto format(const User& u, format_context& ctx) const {
        // 使用 format_to 將數(shù)據(jù)寫入輸出迭代器
        return format_to(ctx.out(), "User[name={}, age={}]", u.name, u.age);
    }
};

    // 特化版本 2: 處理 wchar_t 類型的格式字符串 (e.g., std::wformat)
    template <>
    struct formatter<User, wchar_t> { // 顯式指定第二個(gè)模板參數(shù)為 wchar_t
    using char_type = wchar_t;

    constexpr auto parse(basic_format_parse_context<wchar_t>& ctx) const {
        auto it = ctx.begin();
        auto end = ctx.end();

        if (it == end) {
            return it;
        }

        if (*it != L'}') { // 注意寬字符的 '}'
            throw format_error(L"Invalid format specifier for User (wchar_t).");
        }

        return it;
    }

    auto format(const User& u, wformat_context& ctx) const {
        // 注意使用 L"..." 寬字符串字面量
        return format_to(ctx.out(), L"User[name={}, age={}]", u.name, u.age);
    }
};
}

// --- 3. 主函數(shù),測(cè)試我們的自定義格式化 ---
int main() {
    User u{"Tom", 25};

    // 測(cè)試 1: 使用 char 版本的 std::format
    std::string res = std::format("{}", u);
    std::cout << "std::format result: " << res << '\n';

    // 測(cè)試 2: 使用 wchar_t 版本的 std::wformat
    std::wstring wres = std::wformat(L"{}", u);
    std::wcout << L"std::wformat result: " << wres << L'\n';

    return 0;
}

時(shí)間格式化

C++20 將 <chrono> 時(shí)間庫(kù)與 std::format 進(jìn)行了深度融合??芍苯訉?duì)系統(tǒng)時(shí)間、持續(xù)時(shí)間進(jìn)行高級(jí)格式化:

#include <chrono>
#include <format>
#include <iostream>

int main() {
    auto now = std::chrono::system_clock::now();
    // 原生支持時(shí)間軸格式化輸出
    std::cout << std::format("{:%Y-%m-%d %H:%M:%S}", now);
    return 0;
}
// 示例輸出:2026-06-03 23:37:18

時(shí)間格式控制符規(guī)則與傳統(tǒng)標(biāo)準(zhǔn) C 函數(shù) strftime 完全一致(如 %Y 代表四位數(shù)年份,%m 代表月份,%d 代表日期),詳情可參考《C++之時(shí)間日期庫(kù)chrono》。

異常與校驗(yàn)

編譯期嚴(yán)格校驗(yàn)

在代碼中傳入字面量格式串(Literal string)時(shí),現(xiàn)代編譯器會(huì)在編譯階段通過 constexpr 機(jī)制提前運(yùn)行格式串解析器。一旦發(fā)現(xiàn)占位符數(shù)量與參數(shù)列表不匹配,或者類型對(duì)應(yīng)的格式符錯(cuò)誤(例如對(duì) std::string 使用了 {:d}),將在編譯期直接攔截并拋出編譯錯(cuò)誤。

運(yùn)行時(shí)異常攔截

如果是動(dòng)態(tài)組裝、或運(yùn)行時(shí)從配置文件讀入的非常量格式化字符串,編譯器無法做靜態(tài)前置檢查,錯(cuò)誤將被推遲到運(yùn)行期。此時(shí)格式化引擎會(huì)拋出 std::format_error 異常。

#include <iostream>
#include <format>
#include <string>

int main() {
    try {
        std::string dynamic_fmt = "{:z}"; // 'z' 是針對(duì)整型完全非法的未知格式符
        std::format(dynamic_fmt, 1);
    } catch (const std::format_error& e) {
        // 優(yōu)雅捕獲運(yùn)行期格式化異常,防止服務(wù)崩潰
        std::cerr << "Format error caught: " << e.what() << std::endl;
    }
}

總結(jié)

命名空間限制

自定義類型的 formatter<T> 特化必須顯式置于 namespace std 空間內(nèi),否則格式化引擎在進(jìn)行 ADL 關(guān)聯(lián)模板特化查找時(shí)會(huì)直接宣告失敗并引發(fā)編譯錯(cuò)誤。

窄整型符號(hào)擴(kuò)展

當(dāng)格式化 char 或 unsigned char 變參并指定 {:d} 打印數(shù)值時(shí),容易因?yàn)殡[式符號(hào)擴(kuò)展導(dǎo)致輸出不符合預(yù)期的負(fù)數(shù)數(shù)值。在嚴(yán)謹(jǐn)?shù)母咝阅軋?chǎng)景下,顯式通過 static_cast<int> 進(jìn)行強(qiáng)轉(zhuǎn)切分。

std::format("{:d}", static_cast<int>(ch));

高頻使用示例

// 1. 固定高位補(bǔ)零的十六進(jìn)制大寫輸出
std::string hex_str = std::format("0x{:04X}", 255); // "0x00FF"

// 2. 浮點(diǎn)數(shù)四舍五入保留兩位小數(shù)
std::string fp_str = std::format("{:.2f}", 2.71828); // "2.72"

// 3. 基于動(dòng)態(tài)寬度的靠右填充邊界對(duì)齊
int padding_width = 10;
std::string align_str = std::format("{:*>{}}", 99, padding_width); // "*******99"

到此這篇關(guān)于C++之類型安全格式化format的文章就介紹到這了,更多相關(guān)C++ 類型格式化format內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++ new/delete相關(guān)知識(shí)點(diǎn)詳細(xì)解析

    C++ new/delete相關(guān)知識(shí)點(diǎn)詳細(xì)解析

    C語(yǔ)言用一堆標(biāo)準(zhǔn)庫(kù)函數(shù)malloc和free在自由存儲(chǔ)區(qū)中分配存儲(chǔ)空間,而C++則用new和delete表達(dá)式實(shí)現(xiàn)相同的功能
    2013-09-09
  • C++計(jì)算圖任意兩點(diǎn)間的所有路徑

    C++計(jì)算圖任意兩點(diǎn)間的所有路徑

    這篇文章主要為大家詳細(xì)介紹了C++求圖任意兩點(diǎn)間的所有路徑 ,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-10-10
  • C語(yǔ)言模擬實(shí)現(xiàn)atoi函數(shù)的實(shí)例詳解

    C語(yǔ)言模擬實(shí)現(xiàn)atoi函數(shù)的實(shí)例詳解

    這篇文章主要介紹了C語(yǔ)言模擬實(shí)現(xiàn)atoi函數(shù)的實(shí)例詳解的相關(guān)資料,atoi函數(shù),主要功能是將一個(gè)字符串轉(zhuǎn)變?yōu)檎麛?shù),這里就實(shí)現(xiàn)這樣的函數(shù),需要的朋友可以參考下
    2017-08-08
  • C語(yǔ)言 文件的隨機(jī)讀寫詳解及示例代碼

    C語(yǔ)言 文件的隨機(jī)讀寫詳解及示例代碼

    本文主要介紹C語(yǔ)言 文件的隨機(jī)讀寫,這里整理了相關(guān)資料及示例代碼以便大家學(xué)習(xí)參考,學(xué)習(xí)此部分內(nèi)容的朋友可以參考下
    2016-08-08
  • C語(yǔ)言超詳細(xì)講解getchar函數(shù)的使用

    C語(yǔ)言超詳細(xì)講解getchar函數(shù)的使用

    C 庫(kù)函數(shù) int getchar(void) 從標(biāo)準(zhǔn)輸入 stdin 獲取一個(gè)字符(一個(gè)無符號(hào)字符)。這等同于 getc 帶有 stdin 作為參數(shù),下面讓我們?cè)敿?xì)來看看
    2022-05-05
  • C++實(shí)現(xiàn)掃雷程序開發(fā)

    C++實(shí)現(xiàn)掃雷程序開發(fā)

    這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)掃雷程序開發(fā),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-07-07
  • C++圖文并茂講解繼承

    C++圖文并茂講解繼承

    繼承是C++面向?qū)ο缶幊讨械囊婚T。繼承是子類繼承父類的特征和行為,或者是繼承父類得方法,使的子類具有父類得的特性和行為。重寫是子類對(duì)父類的允許訪問的方法實(shí)行的過程進(jìn)行重新編寫,返回值和形參都不能改變。就是對(duì)原本的父類進(jìn)行重新編寫,但是外部接口不能被重寫
    2022-05-05
  • C語(yǔ)言?深入理解動(dòng)態(tài)規(guī)劃之計(jì)數(shù)類DP

    C語(yǔ)言?深入理解動(dòng)態(tài)規(guī)劃之計(jì)數(shù)類DP

    動(dòng)態(tài)規(guī)劃可謂是大名鼎鼎,筆試面試中的高頻考點(diǎn),也是重點(diǎn)難點(diǎn),動(dòng)態(tài)規(guī)劃類型題目靈活多變,難度系數(shù)也相對(duì)較高,往往我們做不好動(dòng)態(tài)規(guī)劃的題目就會(huì)與心儀的offer失之交臂,本篇文章我們就一起來研究一下動(dòng)態(tài)規(guī)劃的計(jì)數(shù)類DP
    2022-04-04
  • C++事件驅(qū)動(dòng)型銀行排隊(duì)模擬

    C++事件驅(qū)動(dòng)型銀行排隊(duì)模擬

    這篇文章主要為大家詳細(xì)介紹了C++事件驅(qū)動(dòng)型銀行排隊(duì)模擬,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-09-09
  • C++中的strcmp函數(shù)

    C++中的strcmp函數(shù)

    strcmp函數(shù)是C++標(biāo)準(zhǔn)庫(kù)中用于字符串比較的重要函數(shù),在C++中,字符串比較是一項(xiàng)常見的操作,用于判斷兩個(gè)字符串是否相等或者大小關(guān)系,本文介紹C++中的strcmp函數(shù),感興趣的朋友一起看看吧
    2024-03-03

最新評(píng)論

大名县| 扶余县| 孝昌县| 庄河市| 宣汉县| 阜新市| 即墨市| 屏南县| 芮城县| 禹州市| 佛冈县| 岐山县| 江山市| 乌苏市| 扶余县| 柏乡县| 舟山市| 临沂市| 桃源县| 噶尔县| 丰城市| 通江县| 额敏县| 五常市| 措美县| 祁连县| 清水河县| 菏泽市| 大安市| 武夷山市| 安庆市| 慈溪市| 棋牌| 砀山县| 郎溪县| 板桥市| 开封县| 高清| 岳阳市| 始兴县| 宁都县|