文章目录
C语言字符串格式化函数详解
一、sprintf 与 snprintf 对比
1.1 sprintf
int sprintf(char *str, const char *format, ...);
特点:
- 不检查缓冲区大小
- 可能导致缓冲区溢出
- 返回写入的字符数(不包含结束符)
示例:
char buf[10];
int num = 12345;
sprintf(buf, "数字是:%d", num); // 危险!可能溢出
1.2 snprintf
int snprintf(char *str, size_t size, const char *format, ...);
特点:
- 指定缓冲区大小
- 自动截断超长字符串
- 总是添加字符串结束符
- 返回需要的缓冲区长度
示例:
char buf[10];
int num = 12345;
snprintf(buf, sizeof(buf), "数字是:%d", num); // 安全
二、字符串拷贝函数对比
2.1 strncpy
char *strncpy(char *dest, const char *src, size_t n);
特点:
- 不保证目标字符串有结束符
- 如果源字符串小于n,填充0
- 不检查目标缓冲区实际大小
2.2 strncat
char *strncat(char *dest, const char *src, size_t n);
特点:
- 总是添加结束符
- 最多拷贝n个字符
- 可能写入n+1个字符(包括结束符)
三、安全使用实践
3.1 格式化字符串
// 不安全的写法
char buf[50];
int id = 100;
sprintf(buf, "ID=%d", id);
// 安全的写法
char buf[50];
int id = 100;
snprintf(buf, sizeof(buf), "ID=%d", id);
3.2 字符串拼接
// 推荐写法
char result[100];
const char *str1 = "Hello";
const char *str2 = "World";
snprintf(result, sizeof(result), "%s %s", str1, str2);
四、常见错误和防范
4.1 缓冲区溢出
// 错误示例
char small_buf[5];
sprintf(small_buf, "这个字符串太长了"); // 溢出!
// 正确做法
char buf[32];
snprintf(buf, sizeof(buf), "这个字符串太长了");
4.2 格式化字符串漏洞
// 危险的写法
char user_input[100];
sprintf(buf, user_input); // 可能被注入格式化字符串
// 安全的写法
snprintf(buf, sizeof(buf), "%s", user_input);
五、最佳实践
- 始终使用 snprintf 替代 sprintf
#define SAFE_SPRINTF(buf, ...) \
snprintf(buf, sizeof(buf), __VA_ARGS__)
- 检查返回值
char buf[10];
int needed = snprintf(buf, sizeof(buf), "很长的字符串");
if (needed >= sizeof(buf)) {
// 处理截断情况
}
- 字符串长度限制
#define MAX_STR_LEN 100
char buf[MAX_STR_LEN];
snprintf(buf, MAX_STR_LEN, "%.50s", user_input); // 限制输入长度
六、性能考虑
- snprintf 比 sprintf 略慢
- 对于确定安全的场景,可以使用 sprintf
- 关键代码段可以考虑使用 sprintf 优化性能
本文介绍了C语言中的sprintf和snprintf函数,强调了sprintf的安全隐患,如缓冲区溢出,并推荐使用snprintf以确保安全性。文章还提到了strncpy、strncat和snprintf的区别,指出strncpy和strncat可能导致缓冲区未正确填充,而snprintf在缓冲区不足时会自动截断并返回所需长度。
1577

被折叠的 条评论
为什么被折叠?



