C++ 输出格式化技术详解
在 C++ 编程中,格式化输出是常见需求。本文将详细介绍三种主要的输出格式化方法:C 风格的 printf 函数、C++ 流式输出以及 C++20 的 std::format 库。特别关注不同进制(二进制、八进制、十进制、十六进制)的输出实现。
一、C 风格格式输出(兼容传统 C)
C 风格的格式输出通过 printf 函数实现,与 C 语言完全兼容。使用时需要包含 头文件。
常用格式说明符:
| 格式字符 | 功能描述 | 示例代码 |
|---|---|---|
%d |
十进制整数 | printf("数值: %d\n", 100); |
%u |
无符号十进制整数 | printf("无符号: %u\n", 100); |
%o |
八进制表示 | printf("八进制: %o\n", 100); // 输出 144 |
%x / %X |
十六进制小写/大写 | printf("十六进制: %x\n", 100); // 输出 64 |
%#o |
带前缀的八进制 | printf("带前缀八进制: %#o\n", 100); // 输出 0144 |
%#x / %#X |
带前缀的十六进制 | printf("带前缀十六进制: %#x\n", 100); // 输出 0x64 |
%f |
浮点数默认格式 | printf("浮点: %f\n", 3.14159); |
%.2f |
两位小数的浮点数 | printf("两位小数: %.2f\n", 3.14159); |
%e / %E |
科学计数法 | printf("科学计数: %e\n", 1000.0); |
%g / %G |
自动选择 %f 或 %e | printf("自动格式: %g\n", 1000.0); |
二进制输出实现
标准 C 库没有直接提供二进制格式输出,需要自定义函数:
// 自定义二进制输出函数
void display_binary(int num) {
if (num == 0) {
printf("0");
return;
}
char buffer[33]; // 足够存储32位整数的二进制表示
int position = 0;
// 从最低位开始处理
while (num > 0) {
buffer[position++] = (num & 1) ? '1' : '0';
num >>= 1;
}
// 反向输出结果
while (position--) {
putchar(buffer[position]);
}
}
二、C++ 流式输出(面向对象方法)
C++ 提供了面向对象的流式输出机制,主要使用 和 头文件。
进制控制
使用流操纵符控制输出进制:
#include
#include
int main() {
int number = 255;
// 默认十进制
std::cout << "十进制: " << number << std::endl;
// 设置十六进制输出
std::cout << "十六进制: " << std::hex << number << std::endl;
// 设置八进制输出
std::cout << "八进制: " << std::oct << number << std::endl;
// 显示进制前缀
std::cout << std::showbase;
std::cout << "带前缀十六进制: " << std::hex << number << std::endl;
std::cout << "带前缀八进制: " << std::oct << number << std::endl;
// 大写十六进制
std::cout << "大写十六进制: " << std::uppercase << std::hex << number << std::endl;
return 0;
}
二进制输出
使用 std::bitset 实现二进制输出:
#include
#include
void show_binary(int value, int width = 8) {
std::cout << std::bitset(value) << std::endl;
}
int main() {
int num = 42;
std::cout << "8位二进制: ";
show_binary(num, 8);
std::cout << "16位二进制: ";
show_binary(num, 16);
return 0;
}
浮点数格式化
#include
#include
int main() {
double pi = 3.1415926535;
// 默认输出
std::cout << "默认: " << pi << std::endl;
// 固定小数位数
std::cout << std::fixed << std::setprecision(2) << "两位小数: " << pi << std::endl;
// 科学计数法
std::cout << std::scientific << "科学计数: " << pi << std::endl;
return 0;
}
宽度与对齐控制
#include
#include
int main() {
int value = 123;
// 设置输出宽度
std::cout << "宽度8右对齐: " << std::setw(8) << value << std::endl;
// 设置填充字符
std::cout << "宽度8填充0: " << std::setfill('0') << std::setw(8) << value << std::endl;
// 左对齐
std::cout << "左对齐: " << std::left << std::setw(8) << value << std::endl;
return 0;
}
三、C++20 std::format(现代格式化方法)
C++20 引入了类似 Python 和 C# 的格式化库,提供了更简洁、更安全的格式化输出方式。
基本语法
#include
#include
int main() {
int number = 42;
double pi = 3.14159;
// 基本格式化
std::cout << std::format("十进制: {}\n", number);
std::cout << std::format("十六进制: {:x}\n", number);
std::cout << std::format("八进制: {:o}\n", number);
std::cout << std::format("二进制: {:b}\n", number); // C++20新增
// 带前缀的格式
std::cout << std::format("带前缀十六进制: {:#x}\n", number);
std::cout << std::format("带前缀八进制: {:#o}\n", number);
std::cout << std::format("带前缀二进制: {:#b}\n", number);
// 宽度和对齐
std::cout << std::format("右对齐: {:>8}\n", number);
std::cout << std::format("左对齐: {:<8}\n", number);
std::cout << std::format("居中对齐: {:^8}\n", number);
// 浮点数格式
std::cout << std::format("两位小数: {:.2f}\n", pi);
std::cout << std::format("科学计数: {:e}\n", pi);
return 0;
}
常用格式说明符
| 格式说明符 | 功能描述 | 示例输出 |
|---|---|---|
{} |
默认格式 | 42 |
{:d} |
十进制 | 42 |
{:x} / {:X} |
十六进制小写/大写 | 2a / 2A |
{:o} |
八进制 | 52 |
{:b} |
二进制 | 101010 |
{:#x} |
带前缀十六进制 | 0x2a |
{:#o} |
带前缀八进制 | 052 |
{:#b} |
带前缀二进制 | 0b101010 |
{:5d} |
宽度5右对齐 | 42 |
{:05d} |
宽度5补零 | 00042 |
{:.2f} |
两位小数 | 3.14 |
{:8.2f} |
宽度8两位小数 | 3.14 |
{:e} |
科学计数法 | 3.141590e+00 |
四、三种方法对比
| 特性 | C风格 printf | C++ 流式输出 | C++20 std::format |
|---|---|---|---|
| 类型安全 | 否 | 是 | 是 |
| 二进制支持 | 需自定义 | 使用 bitset | 原生支持 {:b} |
| 进制控制 | %o/%x |
操纵符 | {:o}/{:x} |
| 格式字符串 | 复杂 | 分散 | 集中 |
| 性能 | 高 | 中等 | 高 |
| 可读性 | 一般 | 差 | 好 |
| C++标准要求 | C++98 | C++98 | C++20 |
五、选择建议
- 遗留代码或性能关键场景:使用 C 风格的 printf
- 面向对象代码或类型安全要求高:使用 C++ 流式输出
- 现代 C++ 项目(C++20 可用):优先选择 std::format,它提供了最佳的可读性和类型安全性
二进制输出的通用解决方案
#include
#include
template
std::string create_binary_string(IntType value, bool with_prefix = false, int min_width = 0) {
if (value == 0) return with_prefix ? "0b0" : "0";
std::string result;
// 处理负数
if constexpr (std::is_signed_v && value < 0) {
value = -value;
result += '-';
}
// 转换为二进制字符串
while (value > 0) {
result.push_back((value & 1) ? '1' : '0');
value >>= 1;
}
// 反转字符串
std::reverse(result.begin(), result.end());
// 添加前缀
if (with_prefix) result = "0b" + result;
// 添加前导零以达到最小宽度
if (min_width > 0 && (int)result.size() < min_width + (with_prefix ? 2 : 0)) {
result = std::string(min_width + (with_prefix ? 2 : 0) - result.size(), '0') + result;
if (with_prefix) result.insert(2, "0b");
}
return result;
}
使用示例:
int main() {
int num = 42;
std::cout << create_binary_string(num, true, 8) << std::endl; // 0b00101010
return 0;
}