C++ printf 完全指南:从入门到精通

前言

尽管 C++ 提供了 cout 进行输出,但 printf 凭借其格式化的灵活性和高效性,仍然是许多场景下的首选。本文将全面介绍 printf 的用法。

1. 基本语法

#include <cstdio>  // C++ 中使用 cstdio,C语言使用 stdio.h

int printf(const char* format, ...);

2. 格式说明符

2.1 常用格式符

格式符 类型 示例
%d int printf("%d", 123);
%ld long printf("%ld", 123456L);
%lld long long printf("%lld", 123456789LL);
%u unsigned int printf("%u", 123U);
%f float/double printf("%f", 3.14);
%lf double printf("%lf", 3.14159);
%c char printf("%c", 'A');
%s 字符串(char*) printf("%s", "Hello");
%p 指针 printf("%p", ptr);
%x / %X 十六进制 printf("%x", 255); // ff
%o 八进制 printf("%o", 8); // 10
%% 百分号 printf("%%"); // %

2.2 修饰符

// 宽度和精度
printf("%10d", 123);      // 宽度10,右对齐
printf("%-10d", 123);     // 左对齐
printf("%010d", 123);     // 宽度10,前导零填充
printf("%.2f", 3.14159);  // 保留2位小数
printf("%8.3f", 3.14);    // 宽度8,精度3

// 不同进制
printf("%#x", 255);       // 0xff
printf("%#o", 8);         // 010

3. 实际示例

3.1 基础输出

#include <cstdio>

int main() {
    // 整数输出
    printf("整数: %d\n", 42);
    printf("十六进制: %x | 大写: %X\n", 255, 255);
    
    // 浮点数
    printf("浮点数: %f\n", 3.14159);
    printf("保留2位: %.2f\n", 3.14159);
    
    // 字符和字符串
    printf("字符: %c\n", 'A');
    printf("字符串: %s\n", "Hello C++");
    
    // 指针
    int x = 10;
    printf("指针地址: %p\n", &x);
    
    return 0;
}

3.2 格式化对齐

#include <cstdio>

int main() {
    printf("右对齐:\n");
    printf("%10s | %10s\n", "Name", "Score");
    printf("%10s | %10d\n", "Alice", 95);
    printf("%10s | %10d\n", "Bob", 87);
    
    printf("\n左对齐:\n");
    printf("%-10s | %-10s\n", "Name", "Score");
    printf("%-10s | %-10d\n", "Alice", 95);
    printf("%-10s | %-10d\n", "Bob", 87);
    
    return 0;
}

3.3 多变量输出

#include <cstdio>

int main() {
    int age = 25;
    double height = 1.75;
    char grade = 'A';
    
    printf("年龄: %d, 身高: %.2f, 等级: %c\n", 
           age, height, grade);
    
    // 混合格式
    printf("十进制: %d | 八进制: %o | 十六进制: %x\n", 
           100, 100, 100);
    
    return 0;
}

4. 返回值

#include <cstdio>

int main() {
    int count = printf("Hello %s\n", "World");
    printf("输出了 %d 个字符\n", count);
    // 输出: Hello World
    //       输出了 12 个字符
    
    return 0;
}

5. 常见陷阱与注意事项

5.1 类型不匹配

// ❌ 错误示例
long long big = 123456789LL;
printf("%d", big);  // 错误!应该用 %lld

// ✅ 正确示例
printf("%lld", big);

5.2 浮点数精度

double pi = 3.14159265358979;
printf("%.10f\n", pi);  // 3.1415926536 (四舍五入)
printf("%.15f\n", pi);  // 3.141592653589790

5.3 字符串安全

// ⚠️ 危险:可能导致缓冲区溢出
char buffer[10];
sprintf(buffer, "%s", "This string is too long!");

// ✅ 安全:限制长度
snprintf(buffer, sizeof(buffer), "%s", "This string is too long!");

6. 高级技巧

6.1 动态宽度和精度

#include <cstdio>

int main() {
    int width = 10;
    int precision = 3;
    double value = 3.14159;
    
    // 使用 * 动态指定
    printf("%*.*f\n", width, precision, value);
    // 等价于: printf("%10.3f\n", value);
    
    return 0;
}

6.2 printf 与 C++ 混用

#include <iostream>
#include <cstdio>

int main() {
    std::cout << "C++输出: ";
    printf("C风格输出\n");
    
    // 注意:混用可能导致顺序问题
    std::cout << "Hello ";
    printf("World");
    std::cout << " C++" << std::endl;
    // 可能输出: Hello World C++
    
    return 0;
}

7. 性能对比

#include <cstdio>
#include <iostream>
#include <chrono>

int main() {
    const int N = 100000;
    
    // printf 测试
    auto start = std::chrono::high_resolution_clock::now();
    for (int i = 0; i < N; i++) {
        printf("%d ", i);
    }
    auto end = std::chrono::high_resolution_clock::now();
    auto printf_time = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
    
    // cout 测试
    start = std::chrono::high_resolution_clock::now();
    for (int i = 0; i < N; i++) {
        std::cout << i << " ";
    }
    end = std::chrono::high_resolution_clock::now();
    auto cout_time = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
    
    printf("\nprintf耗时: %lld ms\n", printf_time.count());
    printf("cout耗时: %lld ms\n", cout_time.count());
    
    return 0;
}

8. 快速参考卡片

// 整数
%d      // int
%ld     // long
%lld    // long long
%u      // unsigned int
%lu     // unsigned long

// 浮点数
%f      // float/double
%lf     // double
%.2f    // 保留2位小数
%g      // 自动选择%f或%e

// 其他
%c      // 字符
%s      // 字符串
%p      // 指针
%%      // 百分号

// 格式控制
%-10s   // 左对齐宽度10
%10d    // 右对齐宽度10
%05d    // 宽度5,前导零
%#x     // 显示0x前缀

结语

printf 是一个强大且灵活的输出函数,掌握它能让你在 C++ 编程中更加得心应手。记住选择合适的格式说明符,注意类型匹配,就能避免大多数问题。


参考资料