C++ sprintf 函数介绍

本文最后更新于 2025年8月14日 星期四 10:51

sprintf 是个变参函数,作用是打印到字符串。其定义如下:

1
int sprintf (char *__stream, const char *__format, ...);

一、格式化数字字符串

sprintf 最常见的应用为把整型打印到字符串中,所以,sprintf 在大多数场合可以替代 itoa

1
2
3
4
5
6
7
8
9
10
11
12
13
char s[64];
//把整型123打印成一个字符串保存在s中:
sprintf(s, "%d", 123); //s = "123"

//可以指定宽度,不足的左边补空格:
sprintf(s, "%4d%4d", 123, 456); //s = " 123 456"
sprintf(s, "%-4d%4d", 123, 456); //s = "123 456"(左对齐)

//按照16进制打印:
sprintf(s, "%4x", 123); //小写16进制,宽度占8个位置,右对齐
sprintf(s, "%-4X", 123); //大写16进制,宽度占8个位置,左对齐
sprintf(s, "%04X", 123); //s = "007B"(补全前导0,10进制也可)
//8进制需要替换成"%o"

注意一个符号扩展的问题:假如我们想用 16 进制表示短整型 -1,因为一个短整型占 2 个字节,所以我们希望用 4 位 16 进制数来打印它:

1
2
3
short s1 = -1;
sprintf(s, "%04X", s1); //s = "FFFFFFFF"
sprintf(s, "%04X", (unsigned short)s1); //s = "FFFF"

产生 "FFFFFFFF",是因为 sprintf 是个变参函数,除前两个参数外,后面的参数都不是类型安全的,函数更没有办法仅仅通过一个 “%X” 就能得知当初函数调用前参数压栈时被压进来的到底是个 4 字节的整型还是个 2 字节的短整型,所以采取了统一 4 字节的处理方式,导致参数压栈时做了符号扩展,扩展成了 32 位的整型 -1,打印时 4 个位置不够了,就把 32 位整型 -1 的 8 位 16 进制都打印出来了。

注意 8 进制和 16 进制都不会打印出负数,都是无符号的,实际上也就是变量的内部编码的直接的 16 进制或 8 进制表示。

二、打印浮点数

浮点数使用格式符 "%f" 控制,默认保留小数点后 6 位数字:

1
2
3
4
5
6
sprintf(s, "%f", 3.1415926);  //s = "3.141593"

//"%m.nf"格式,其中 m 表示打印的宽度,n 表示小数点后的位数。
sprintf(s, "%8.3f", 3.1415626); //s = " 3.142"
sprintf(s, "%-8.3f", 3.1415626); //s = "3.142 "
sprintf(s, "%.3f", 3.1415626); //s = "3.142"(不指定总宽度)
  • 注意浮点数:
1
2
sprintf(s, "%.2f", 1);  //s = "0.00"
sprintf(s, "%.2f", (double)1); //s = "1.00"

三、连接字符串

sprintf 能够连接字符串,在许多场合可以替代 strcat,并且它可以同时在字符串中间插入别的内容,非常灵活。如:

1
2
3
char* s1 = "Hello";
char* s2 = "world";
sprintf(s, "%s, %s!", s1, s2); //s = "Hello, world!"

打印字符串也可以指定宽度:

1
2
3
4
5
6
7
8
9
10
11
12
13
char a1[] = {'A', 'B', 'C'};
char a2[] = {'D', 'E', 'F'};
sprintf(s, "%s%s", a1, a2); //s = ABCDEFABCABC(错误)
sprintf(s, "%3s%3s", a1, a2); //s = ABCABCABCABCABCDEFABCABCABCABCABCABC(错误)
sprintf(s, "%.3s%.3s", a1, a2); //s = "ABCDEF"(正确)

//只取部分字符:
sprintf(s, "%.1s%.2s", a1, a2); //s = "ADE"
sprintf(s, "%.*s%.*s", 1, a1, 2, a2); //s = "ADE"
sprintf(s, "%.*s%.*s", sizeof(a1), a1, sizeof(a2), a2); //s = "ABCDEF"

sprintf(s, "%#0*X", 8, 128); //s = "0X000080","#"的作用是打印0X
sprintf(s, "%*.*f", 10, 2, 3.1415926); //s = " 3.14"

四、打印地址信息

有时调试程序时,我们可能想查看某些变量或者成员的地址,由于地址或者指针也不过是个 32 位的数,你可以打印地址信息:

1
2
3
4
5
int i;
sprintf(s, "%u", &i); //10进制地址
sprintf(s, "%08X", &i); //16进制地址
sprintf(s, "%p", &i); //sprintf专门提供的"%p"
sprintf(s, "%0*x", 2 * sizeof(void *), &i); //与第三种方法接近

五、利用 sprintf 的返回值

sprintf 返回了本次函数调用最终打印到字符缓冲区中的字符数目。也就是说每当一次 sprintf 调用结束以后,无须再调用一次 strlen 就能知道结果字符串的长度。如:

1
int len = sprintf(s, "%d", i);

对于正整数来说,len 便等于整数 i 的 10 进制位数。

下面的是个完整的例子,产生 10 个 [0, 100) 之间的随机数,并将他们打印到一个字符数组 s 中,以逗号分隔开。

1
2
3
4
5
6
7
8
9
10
11
12
#include <bits\stdc++.h>
int main() {
srand(time(0));
char s[64];
int offset = 0;
for (int i = 1; i <= 10; i++) {
offset += sprintf(s + offset, "%d,", rand() % 100);
}
s[offset - 1] = '/n'; //将最后一个逗号换成换行符
printf(s);
return 0;
}

六、strftime

strftime 专门用于格式化时间字符串,用法跟 sprintf 很像,但要调用者指定缓冲区的最大长度。如:

1
2
3
time_t t = time(0);  //时间戳
char s[64];
strftime(s, sizeof(s), "%Y-%m-%d %H:%M:%S", localtime(&t)); //产生"YYYY-MM-DD hh:mm:ss"格式的字符串

sprintf 在 MFC 中对应 CString::Format,strftime 在 MFC 中对应 CTime::Format

本文部分内容整理自互联网。


C++ sprintf 函数介绍
https://blog.gtbcamp.cn/article/cpp-sprintf-strftime/
作者
Great Thunder Brother
发布于
2022年9月10日
更新于
2025年8月14日
许可协议