【Spdlog】fmt::format格式化字段输出
spdlog 直接集成了 fmt 库,所以所有 fmt 格式化语法都适用
0. 格式说明符语法结构
格式说明符的完整语法是:
{[参数索引]:[对齐][符号][#][0][宽度][.精度][类型]}
关键总结:
-
整型格式化:
-
{:d}- 十进制 -
{:x}- 小写十六进制 -
{:X}- 大写十六进制 -
{:#x}- 带0x前缀的小写十六进制 -
{:#X}- 带0X前缀的大写十六进制
-
-
无符号整型:直接使用相同的格式说明符
-
科学计数法:
-
{:e}- 小写e -
{:E}- 大写E -
{:.3e}- 保留3位小数的小写科学计数法
-
-
宽度和填充:
-
{:8}- 宽度8 -
{:08}- 宽度8,填充0 -
{:>8}- 右对齐宽度8 -
{:<8}- 左对齐宽度8
-
-
对齐语法:
-
<- 左对齐 -
>- 右对齐(默认) -
^- 居中对齐
-
-
精度语法:
-
浮点数:
{:.3f}(3位小数) -
科学计数法:
{:.2e}(2位小数)
-
-
组合语法:
{:<10.2f}(左对齐,宽度10,精度2的浮点数) -
填充字符:在
<、>、^前指定,如{:*>10}(用*填充右对齐) -
十六进制格式:
{:#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; }
关键点总结:
-
所有格式化都通过
std::string aa = fmt::format(...)实现 -
格式说明符语法完整示例:
// 宽度 + 对齐 + 精度 + 类型 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|
-
动态格式化:使用嵌套的
{}指定动态参数int width = 10, precision = 3; aa = fmt::format("|{:{}.{}f}|", 123.456, width, precision);
-
运行时格式字符串:使用
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格式

浙公网安备 33010602011771号