【Spdlog】fmt::format格式化字段输出

spdlog 直接集成了 fmt 库,所以所有 fmt 格式化语法都适用

 

0. 格式说明符语法结构

格式说明符的完整语法是: 

{[参数索引]:[对齐][符号][#][0][宽度][.精度][类型]}

关键总结: 

  1. 整型格式化:

    • {:d} - 十进制

    • {:x} - 小写十六进制

    • {:X} - 大写十六进制

    • {:#x} - 带0x前缀的小写十六进制

    • {:#X} - 带0X前缀的大写十六进制

  2. 无符号整型:直接使用相同的格式说明符

  3. 科学计数法:

    • {:e} - 小写e

    • {:E} - 大写E

    • {:.3e} - 保留3位小数的小写科学计数法

  4. 宽度和填充:

    • {:8} - 宽度8

    • {:08} - 宽度8,填充0

    • {:>8} - 右对齐宽度8

    • {:<8} - 左对齐宽度8 

  1. 对齐语法:

    • < - 左对齐

    • > - 右对齐(默认)

    • ^ - 居中对齐

  2. 精度语法:

    • 浮点数:{:.3f}(3位小数)

    • 科学计数法:{:.2e}(2位小数)

  3. 组合语法:{:<10.2f}(左对齐,宽度10,精度2的浮点数)

  4. 填充字符:在<>^前指定,如{:*>10}(用*填充右对齐)

  5. 十六进制格式:{:#08x}(带0x前缀,宽度8,填充0,小写十六进制)

下面使用 std::string aa = fmt::format(...) 的方式来实现各种格式化输出:

1. 基本数值格式化

#include <string>
#include <iostream>
#include <fmt/format.h>  // 或者 spdlog/fmt/fmt.h

int main() {
    int num = 255;
    unsigned int unum = 4294967295u;
    double sci_num = 12345.6789;
    
    // 十进制输出
    std::string aa = fmt::format("十进制: {}", num);
    std::cout << aa << std::endl;                    // 十进制: 255
    
    aa = fmt::format("十进制(无符号): {}", unum);
    std::cout << aa << std::endl;                    // 十进制(无签名): 4294967295
    
    // 十六进制输出
    aa = fmt::format("小写十六进制: {:x}", num);
    std::cout << aa << std::endl;                    // 小写十六进制: ff
    
    aa = fmt::format("大写十六进制: {:X}", num);
    std::cout << aa << std::endl;                    // 大写十六进制: FF
    
    aa = fmt::format("带前缀小写十六进制: {:#x}", num);
    std::cout << aa << std::endl;                    // 带前缀小写十六进制: 0xff
    
    aa = fmt::format("带前缀大写十六进制: {:#X}", num);
    std::cout << aa << std::endl;                    // 带前缀大写十六进制: 0XFF
    
    // 科学计数法
    aa = fmt::format("科学计数法(小写e): {:e}", sci_num);
    std::cout << aa << std::endl;                    // 科学计数法(小写e): 1.234568e+04
    
    aa = fmt::format("科学计数法(大写E): {:E}", sci_num);
    std::cout << aa << std::endl;                    // 科学计数法(大写E): 1.234568E+04
    
    return 0;
}

2. 宽度和对齐控制

#include <string>
#include <iostream>
#include <fmt/format.h>

int main() {
    int num = 42;
    double fnum = 123.456;
    
    std::cout << "========== 宽度控制 ==========" << std::endl;
    
    // 基础宽度
    std::string aa = fmt::format("宽度10: |{:10}|", num);
    std::cout << aa << std::endl;                    // |        42|
    
    aa = fmt::format("宽度10: |{:10}|", fnum);
    std::cout << aa << std::endl;                    // |   123.456|
    
    // 十六进制宽度
    aa = fmt::format("十六进制宽度8: |{:8x}|", 0xFF);
    std::cout << aa << std::endl;                    // |      ff|
    
    aa = fmt::format("十六进制宽度8: |{:8X}|", 0xFF);
    std::cout << aa << std::endl;                    // |      FF|
    
    // 组合宽度和类型
    aa = fmt::format("十六进制宽度8填充0: |{:08x}|", 0xFF);
    std::cout << aa << std::endl;                    // |000000ff|
    
    aa = fmt::format("十六进制宽度8带前缀: |{:#10x}|", 0xFF);
    std::cout << aa << std::endl;                    // |     0xff|
    
    std::cout << "\n========== 对齐方式 ==========" << std::endl;
    
    // 左对齐 <
    aa = fmt::format("左对齐: |{:<10}|", num);
    std::cout << aa << std::endl;                    // |42        |
    
    // 右对齐 >(默认)
    aa = fmt::format("右对齐: |{:>10}|", num);
    std::cout << aa << std::endl;                    // |        42|
    
    // 居中对齐 ^
    aa = fmt::format("居中对齐: |{:^10}|", num);
    std::cout << aa << std::endl;                    // |    42    |
    
    // 十六进制对齐
    aa = fmt::format("十六进制左对齐: |{:<10x}|", 0xFF);
    std::cout << aa << std::endl;                    // |ff        |
    
    aa = fmt::format("十六进制右对齐: |{:>10X}|", 0xFF);
    std::cout << aa << std::endl;                    // |        FF|
    
    // 带填充字符的对齐
    aa = fmt::format("填充*居中: |{:*^10}|", num);
    std::cout << aa << std::endl;                    // |****42****|
    
    aa = fmt::format("填充-右对齐: |{:->10}|", num);
    std::cout << aa << std::endl;                    // |--------42|
    
    return 0;
}

3. 浮点数精度控制

#include <string>
#include <iostream>
#include <fmt/format.h>
#include <cmath>

int main() {
    double pi = M_PI;
    double large_num = 1234567.8901234567;
    double small_num = 0.00000123456789;
    
    std::cout << "========== 浮点数精度控制 ==========" << std::endl;
    
    // 定点表示法的精度
    std::string aa = fmt::format("默认精度: {}", pi);
    std::cout << aa << std::endl;                    // 3.141592653589793
    
    aa = fmt::format("精度2位: {:.2f}", pi);
    std::cout << aa << std::endl;                    // 3.14
    
    aa = fmt::format("精度5位: {:.5f}", pi);
    std::cout << aa << std::endl;                    // 3.14159
    
    aa = fmt::format("精度10位: {:.10f}", pi);
    std::cout << aa << std::endl;                    // 3.1415926536
    
    // 科学计数法的精度
    aa = fmt::format("科学计数精度2位: {:.2e}", large_num);
    std::cout << aa << std::endl;                    // 1.23e+06
    
    aa = fmt::format("科学计数精度5位: {:.5e}", small_num);
    std::cout << aa << std::endl;                    // 1.23457e-06
    
    aa = fmt::format("科学计数精度2位(大写): {:.2E}", large_num);
    std::cout << aa << std::endl;                    // 1.23E+06
    
    // 自动选择表示法的精度
    aa = fmt::format("自动选择精度2位: {:.2g}", large_num);
    std::cout << aa << std::endl;                    // 1.2e+06
    
    aa = fmt::format("自动选择精度5位: {:.5g}", pi);
    std::cout << aa << std::endl;                    // 3.1416
    
    return 0;
}

4. 组合使用示例

#include <string>
#include <iostream>
#include <fmt/format.h>

int main() {
    std::cout << "========== 组合格式化 ==========" << std::endl;
    
    // 整数:宽度 + 对齐 + 进制
    std::string aa = fmt::format("整数组合: |{:0>10d}|", 42);
    std::cout << aa << std::endl;                    // |0000000042|
    
    aa = fmt::format("整数组合: |{:*<10x}|", 255);
    std::cout << aa << std::endl;                    // |ff********|
    
    aa = fmt::format("整数组合: |{:#^12X}|", 0xBEEF);
    std::cout << aa << std::endl;                    // |  0XBEEF   |
    
    // 浮点数:宽度 + 对齐 + 精度
    aa = fmt::format("浮点数组合: |{:>10.2f}|", 123.456);
    std::cout << aa << std::endl;                    // |    123.46|
    
    aa = fmt::format("浮点数组合: |{:<10.4f}|", 123.456);
    std::cout << aa << std::endl;                    // |123.4560  |
    
    aa = fmt::format("浮点数组合: |{:^12.3e}|", 123456.789);
    std::cout << aa << std::endl;                    // | 1.235e+05  |
    
    // 带填充的十六进制
    aa = fmt::format("十六进制组合: |{:#010x}|", 255);
    std::cout << aa << std::endl;                    // |0x000000ff|
    
    aa = fmt::format("十六进制组合: |{:#<12X}|", 0xABCD);
    std::cout << aa << std::endl;                    // |0XABCD######|
    
    return 0;
}

5. 实际应用:表格输出

 

#include <string>
#include <iostream>
#include <vector>
#include <fmt/format.h>

struct SensorData {
    int id;
    unsigned int raw_value;
    double voltage;
    double temperature;
};

int main() {
    std::vector<SensorData> sensors = {
        {1, 0x1A3F, 3.14159265, 25.123456},
        {2, 0xBEEF, 5.0, -10.56789},
        {3, 0x00FF, 12.3456789, 100.0},
        {4, 0xABCD, 0.00123456, 0.0}
    };
    
    // 打印表头
    std::string aa = fmt::format("传感器数据表");
    std::cout << aa << std::endl;
    
    aa = fmt::format("{:─^80}", "");
    std::cout << aa << std::endl;
    
    aa = fmt::format("{:<4} | {:<10} | {:<12} | {:<15} | {:<20}",
                     "ID", "原始值(Hex)", "电压(V)", "温度(℃)", "科学表示");
    std::cout << aa << std::endl;
    
    aa = fmt::format("{:─^80}", "");
    std::cout << aa << std::endl;
    
    // 打印数据行
    for (const auto& sensor : sensors) {
        aa = fmt::format("{:<4} | {:#<10X} | {:>12.4f} | {:>15.3f} | {:>20.3e}",
                         sensor.id,
                         sensor.raw_value,       // 左对齐,宽度10,大写十六进制
                         sensor.voltage,         // 右对齐,宽度12,精度4
                         sensor.temperature,     // 右对齐,宽度15,精度3
                         sensor.temperature);    // 右对齐,宽度20,科学计数法精度3
        std::cout << aa << std::endl;
    }
    
    aa = fmt::format("{:─^80}", "");
    std::cout << aa << std::endl;
    
    return 0;
}

6. 动态宽度和精度

#include <string>
#include <iostream>
#include <fmt/format.h>

int main() {
    std::cout << "========== 动态宽度和精度 ==========" << std::endl;
    
    // 通过参数动态指定宽度
    int width = 15;
    int precision = 6;
    double value = 123.456789;
    
    // 方法1:使用嵌套格式
    std::string aa = fmt::format("动态宽度: |{:{}}|", value, width);
    std::cout << aa << std::endl;                     // |     123.457|
    
    aa = fmt::format("动态宽度精度: |{:{}.{}f}|", value, width, precision);
    std::cout << aa << std::endl;                     // |    123.456789|
    
    // 方法2:科学计数法的动态精度
    aa = fmt::format("动态科学计数: |{:.{}e}|", value, precision);
    std::cout << aa << std::endl;                     // |1.234568e+02|
    
    // 方法3:十六进制的动态宽度
    int hex_width = 8;
    aa = fmt::format("动态十六进制宽度: |{:0{}x}|", 255, hex_width);
    std::cout << aa << std::endl;                     // |000000ff|
    
    aa = fmt::format("动态十六进制带前缀: |{:#0{}X}|", 255, hex_width+2);
    std::cout << aa << std::endl;                     // |0X0000FF|
    
    return 0;
}

7. 格式化工具函数

#include <string>
#include <iostream>
#include <vector>
#include <fmt/format.h>

// 格式化十六进制,可控制宽度、对齐、大小写、前缀
std::string formatHex(uint64_t value, 
                     int width = 0, 
                     char align = '>', 
                     bool uppercase = false,
                     bool showPrefix = false) {
    std::string formatStr = "{:";
    
    // 对齐
    if (align != '>') {  // 默认是右对齐
        formatStr += align;
    }
    
    // 填充和宽度
    if (width > 0) {
        if (showPrefix) {
            formatStr += "0";  // 使用0填充时
        }
        formatStr += std::to_string(width);
    }
    
    // 前缀
    if (showPrefix) {
        formatStr += "#";
    }
    
    // 类型
    formatStr += uppercase ? "X}" : "x}";
    
    return fmt::format(fmt::runtime(formatStr), value);
}

// 格式化科学计数法,可控制精度、宽度、对齐、大小写
std::string formatScientific(double value,
                            int precision = 6,
                            int width = 0,
                            char align = '>',
                            bool uppercase = false) {
    std::string formatStr = "{:";
    
    // 对齐
    if (align != '>') {
        formatStr += align;
    }
    
    // 宽度
    if (width > 0) {
        formatStr += std::to_string(width);
    }
    
    // 精度
    formatStr += "." + std::to_string(precision);
    
    // 类型
    formatStr += uppercase ? "E}" : "e}";
    
    return fmt::format(fmt::runtime(formatStr), value);
}

int main() {
    std::cout << "========== 格式化工具函数示例 ==========" << std::endl;
    
    // 使用工具函数
    std::cout << "十六进制格式化:" << std::endl;
    
    std::string aa = formatHex(0xABCD);
    std::cout << "默认: " << aa << std::endl;           // abcd
    
    aa = formatHex(0xABCD, 8);
    std::cout << "宽度8: " << aa << std::endl;          //     abcd
    
    aa = formatHex(0xABCD, 10, '<');
    std::cout << "左对齐宽度10: " << aa << std::endl;   // abcd      
    
    aa = formatHex(0xABCD, 12, '>', false, true);
    std::cout << "带前缀宽度12: " << aa << std::endl;   //        0xabcd
    
    aa = formatHex(0xBEEF, 0, '>', true, true);
    std::cout << "大写带前缀: " << aa << std::endl;     // 0XBEEF
    
    std::cout << "\n科学计数法格式化:" << std::endl;
    
    aa = formatScientific(123456.789);
    std::cout << "默认: " << aa << std::endl;           // 1.234568e+05
    
    aa = formatScientific(123456.789, 3);
    std::cout << "精度3: " << aa << std::endl;          // 1.235e+05
    
    aa = formatScientific(123456.789, 4, 0, '>', true);
    std::cout << "大写精度4: " << aa << std::endl;      // 1.2346E+05
    
    aa = formatScientific(123456.789, 2, 15);
    std::cout << "宽度15精度2: " << aa << std::endl;    //       1.23e+05
    
    return 0;
}

8. 复杂组合示例

#include <string>
#include <iostream>
#include <fmt/format.h>

int main() {
    std::cout << "========== 复杂组合示例 ==========" << std::endl;
    
    // 创建带格式的数据行
    struct DataRow {
        const char* name;
        int int_value;
        unsigned int hex_value;
        double sci_value;
        double float_value;
    };
    
    std::vector<DataRow> data = {
        {"Alpha", 100, 0x00FF, 1.23456e-6, 123.456},
        {"Beta", -200, 0xABCD, 9.87654e+9, -987.654},
        {"Gamma", 3000, 0x1234, 5.43210e-3, 0.001234},
        {"Delta", -40000, 0xFEDC, 2.10987e+12, 999999.999}
    };
    
    // 使用复杂格式字符串
    const std::string format_str = 
        "| {:<10} | {:>+10d} | {:#<10X} | {:>15.3e} | {:>12.4f} |";
    
    // 表头
    std::string aa = fmt::format("| {:<10} | {:<10} | {:<10} | {:<15} | {:<12} |",
                                 "Name", "Integer", "Hex", "Scientific", "Float");
    std::cout << aa << std::endl;
    
    aa = fmt::format("|{:-<12}|{:-<12}|{:-<12}|{:-<17}|{:-<14}|",
                     "", "", "", "", "");
    std::cout << aa << std::endl;
    
    // 数据行
    for (const auto& item : data) {
        aa = fmt::format(fmt::runtime(format_str),
                         item.name,
                         item.int_value,     // 带符号,右对齐,宽度10
                         item.hex_value,     // 带前缀,左对齐,宽度10,大写十六进制
                         item.sci_value,     // 右对齐,宽度15,科学计数法精度3
                         item.float_value);  // 右对齐,宽度12,定点数精度4
        std::cout << aa << std::endl;
    }
    
    return 0;
}

9. 批量格式化存储

#include <string>
#include <iostream>
#include <vector>
#include <fmt/format.h>

int main() {
    std::vector<int> numbers = {10, 255, 4096, 65535};
    std::vector<std::string> formatted_strings;
    
    // 批量格式化为不同进制
    for (int num : numbers) {
        // 十进制
        std::string aa = fmt::format("十进制: {:6d}", num);
        formatted_strings.push_back(aa);
        
        // 十六进制小写
        aa = fmt::format("十六进制小写: {:6x}", num);
        formatted_strings.push_back(aa);
        
        // 十六进制大写带前缀
        aa = fmt::format("十六进制大写: {:#6X}", num);
        formatted_strings.push_back(aa);
    }
    
    // 输出所有格式化后的字符串
    std::cout << "批量格式化结果:" << std::endl;
    for (const auto& str : formatted_strings) {
        std::cout << str << std::endl;
    }
    
    return 0;
}

10. 格式化配置示例

#include <string>
#include <iostream>
#include <fmt/format.h>

struct FormatConfig {
    int width;
    int precision;
    bool uppercase;
    bool show_prefix;
    char align;
    
    std::string formatInt(int value) const {
        return fmt::format("{:{}{}d}", value, align, width);
    }
    
    std::string formatHex(unsigned int value) const {
        std::string fmt_str = "{:";
        fmt_str += align;
        if (show_prefix) fmt_str += "#";
        fmt_str += std::to_string(width);
        fmt_str += uppercase ? "X}" : "x}";
        return fmt::format(fmt::runtime(fmt_str), value);
    }
    
    std::string formatScientific(double value) const {
        return fmt::format("{:{}{}.{}e}", value, align, width, precision);
    }
};

int main() {
    FormatConfig config1 = {10, 3, true, true, '>'};
    FormatConfig config2 = {8, 6, false, false, '<'};
    FormatConfig config3 = {15, 4, true, false, '^'};
    
    int int_val = 42;
    unsigned int hex_val = 0xBEEF;
    double sci_val = 12345.6789;
    
    std::cout << "配置1 (宽度10, 精度3, 大写, 有前缀, 右对齐):" << std::endl;
    std::string aa = config1.formatInt(int_val);
    std::cout << "整数: " << aa << std::endl;                     // |        42|
    
    aa = config1.formatHex(hex_val);
    std::cout << "十六进制: " << aa << std::endl;                 // |    0XBEEF|
    
    aa = config1.formatScientific(sci_val);
    std::cout << "科学计数: " << aa << std::endl;                 // | 1.235E+04|
    
    std::cout << "\n配置2 (宽度8, 精度6, 小写, 无前缀, 左对齐):" << std::endl;
    aa = config2.formatInt(int_val);
    std::cout << "整数: " << aa << std::endl;                     // |42      |
    
    aa = config2.formatHex(hex_val);
    std::cout << "十六进制: " << aa << std::endl;                 // |beef    |
    
    aa = config2.formatScientific(sci_val);
    std::cout << "科学计数: " << aa << std::endl;                 // |1.234568e+04|
    
    return 0;
}

关键点总结:

  1. 所有格式化都通过 std::string aa = fmt::format(...) 实现

  2. 格式说明符语法完整示例

    // 宽度 + 对齐 + 精度 + 类型
    std::string aa = fmt::format("|{:<10.2f}|", 123.456);  // 左对齐,宽度10,精度2
    
    // 十六进制:带前缀,填充0,宽度8
    aa = fmt::format("|{:#08x}|", 255);  // |0x0000ff|
    
    // 科学计数法:宽度15,精度3,大写E
    aa = fmt::format("|{:>15.3E}|", 123456.789);  // |      1.235E+05|
  3. 动态格式化:使用嵌套的 {} 指定动态参数

    int width = 10, precision = 3;
    aa = fmt::format("|{:{}.{}f}|", 123.456, width, precision);
  4. 运行时格式字符串:使用 fmt::runtime() 处理动态格式字符串

    std::string fmt_str = "{:#0{}X}";
    aa = fmt::format(fmt::runtime(fmt_str), 255, 8);

这种方式可以将格式化结果保存到字符串中,便于后续处理或输出


 

在C++中,你可以使用 fmt::format 配合 std::vector<uint8_t> 或数组来生成十六进制字符串,并输出JSON格式

方法1:使用fmt的内置格式化功能(推荐)

#include <fmt/format.h>
#include <vector>
#include <cstdint>
#include <string>

std::string bytes_to_hex_json(const std::vector<uint8_t>& bytes) {
    // 使用fmt::format直接生成十六进制字符串
    std::string hex_str = fmt::format("\"0x{:02x}\"", fmt::join(bytes, ", 0x"));
    
    // 包装成JSON对象
    return fmt::format("{{\"hex\": [{}]}}", hex_str);
}

 

 
 

在C++中,你可以使用 fmt::format 配合 std::vector<uint8_t> 或数组来生成十六进制字符串,并输出JSON格式
posted @ 2025-12-17 10:35  我自逍遥笑  阅读(17)  评论(0)    收藏  举报