介绍
snprintf 是 C 标准库(<stdio.h>)中安全的格式化字符串写入函数,核心是通过限制最大写入长度防止缓冲区溢出,是 sprintf 的安全替代。
函数原型
#include <stdio.h>
int snprintf(char *restrict str, size_t size, const char *restrict format, ...);
参数说明
- str:目标字符缓冲区,用于存放格式化后的字符串。
- size:缓冲区总大小(包含末尾
\0 终止符)。函数最多写入 size-1 个有效字符,最后自动补 \0。 - format:格式化字符串(与
printf 一致,如 %d、%s、%f 等)。 - …:可变参数列表,对应
format 中的占位符。
返回值
- 成功:返回本该写入的字符总数(不含末尾
\0),无论是否被截断。 - 失败:返回负数(如格式化错误、编码异常)。
使用说明
- 当格式化后内容长度 <
size:完整写入,末尾补 \0。 - 当格式化后内容长度 ≥
size:自动截断,只写入前 size-1 个字符,末尾强制补 \0,保证字符串合法。 - 若
size = 0:不写入任何内容,str 可为 NULL。
示例代码
#include <stdio.h>
#include <string.h>
int main() {
char buf[10]; // 缓冲区大小 10
int ret;
// 场景1:内容未超出缓冲区
ret = snprintf(buf, sizeof(buf), "num: %d", 123);
printf("buf: %s | ret: %d | strlen: %zu\n", buf, ret, strlen(buf));
// 输出:buf: num: 123 | ret: 6 | strlen: 6
// 场景2:内容超出缓冲区(自动截断)
ret = snprintf(buf, sizeof(buf), "long: %s", "abcdefghijklmn");
printf("buf: %s | ret: %d | strlen: %zu\n", buf, ret, strlen(buf));
// 输出:buf: long: abc | ret: 15 | strlen: 9
// 场景3:根据返回值动态分配足够空间
const char *long_str = "this is a very long string";
ret = snprintf(NULL, 0, "%s", long_str); // 先获取所需长度
if (ret >= 0) {
char *dyn_buf = malloc(ret + 1);
if (dyn_buf) {
snprintf(dyn_buf, ret + 1, "%s", long_str);
printf("dyn_buf: %s\n", dyn_buf);
free(dyn_buf);
}
}
return 0;
}
与 sprintf 的关键区别
| 特性 |
snprintf |
sprintf |
| 安全性 |
安全,限制长度,防溢出 |
不安全,无长度检查,易溢出 |
| 返回值 |
本该写入的字符数(不含 \0) |
实际写入的字符数(不含 \0) |
| 截断 |
自动截断并补 \0 |
不截断,直接溢出 |
| 标准 |
C99 标准 |
C89/C99 均支持 |
注意
- 固定缓冲区安全写入:优先用
snprintf 替代 sprintf,传入 sizeof(buf) 作为 size。 - 动态分配足够空间:先用
snprintf(NULL, 0, ...) 获取所需长度,再 malloc 分配,避免截断。 - 判断是否截断:若返回值
ret >= (int)size,说明内容被截断。 - 避免重叠内存:
str 与源字符串/参数内存重叠时,行为未定义。
% 格式说明符
% 是格式化占位符,用来告诉 snprintf 把变量按什么格式写入字符串。我直接给你最常用、最实用、开发必背的全套说明符,配例子,一看就会。
1. 整数类型
| 说明符 |
作用 |
示例 |
%d / %i |
十进制 int 整数 |
snprintf(s, len, "%d", 123); → "123" |
%u |
无符号十进制整数 |
%u → 只显示正数 |
%x |
小写十六进制 |
%x → 1a |
%X |
大写十六进制 |
%X → 1A |
%o |
八进制 |
%o → 32 |
2. 长整数 / 64位整数
| 说明符 |
作用 |
%ld |
long 整数 |
%lld |
long long 整数(64位) |
%lu |
unsigned long |
%llu |
unsigned long long |
3. 字符与字符串
| 说明符 |
作用 |
示例 |
%c |
单个字符 |
%c → 'A' |
%s |
字符串 |
%s → "hello" |
4. 浮点数
| 说明符 |
作用 |
%f |
float / double 浮点数 |
%.2f |
保留 2位小数(最常用) |
%e |
科学计数法(小写) |
%E |
科学计数法(大写) |
5. 指针地址
高级格式控制
1. 固定宽度、补零
%5d:占 5个字符宽度,不足补空格%05d:占 5个字符宽度,不足补 0
例子:
snprintf(buf, 10, "%05d", 12);
// 结果:00012
2. 保留小数位数
snprintf(buf, 20, "%.2f", 3.14159);
// 结果:3.14
3. 左右对齐
例子
#include <stdio.h>
int main() {
char buf[100];
// 整数
snprintf(buf, sizeof(buf), "整数:%d", 100);
printf("%s\n", buf); // 整数:100
// 十六进制
snprintf(buf, sizeof(buf), "十六进制:%X", 26);
printf("%s\n", buf); // 十六进制:1A
// 字符串 + 字符
snprintf(buf, sizeof(buf), "姓名:%s,等级:%c", "小明", 'A');
printf("%s\n", buf); // 姓名:小明,等级:A
// 浮点数(保留2位)
snprintf(buf, sizeof(buf), "价格:%.2f", 19.99);
printf("%s\n", buf); // 价格:19.99
// 固定宽度补0
snprintf(buf, sizeof(buf), "编号:%04d", 8);
printf("%s\n", buf); // 编号:0008
return 0;
}