C语言的库函数中有很多老破旧是不检查越界的。所以后来出了很多函数名带n的替代品。
snprintf
不仅加上了n还会自动给补0。
函数声明:
int snprintf(char * restrict str, size_t size, const char * restrict format, ...);
代码示例
#include <iostream>
#include <string>
#include <stdio.h>
#include <string.h>
using namespace std;
int main()
{
char sz[100];
string str = "abcd";
cout<<sizeof(sz)<<endl; // 100
// str.c_str() 等于 str.data()
cout<<sizeof(str.c_str())<<endl; // 8
cout<<strlen(str.c_str())<<endl; // 4
// str.size() 等于 str.length()
cout<<str.size()<<endl; // 4
int ia = snprintf(sz, sizeof(str.c_str()), "%s", str.c_str());
cout<<sz<<endl; // abcd
cout<<sizeof(sz)<<endl; // 100
int ib = snprintf(sz, strlen(str.c_str()), "%s", str.c_str());
cout<<sz<<endl; // abc
cout<<ia<<endl; // 4
cout<<ib<<endl; // 4
return 0;
}
可以看出 strlen(str.c_str()) 等价于 str.size() 都是实际字符的大小。
但是snprintf的中的参数size(第二个参数)需要比这个数字大。
snprintf默认拷贝size-1个字符,然后会给第size的字符赋值 ‘\0’。
#include <iostream>
#include <string>
#include <stdio.h>
#include <string.h>
using namespace std;
int main()
{
char sz[3];
string str = "abcd";
cout<<sizeof(sz)<<endl; // 3
int ia = snprintf(sz, sizeof(str.c_str()), "%s", str.c_str());
cout<<sz<<endl; // abcd
cout<<sizeof(sz)<<endl; // 3
cout<<strlen(sz)<<endl; // 4
int ib = snprintf(sz, strlen(str.c_str()), "%s", str.c_str());
cout<<sz<<endl; // abc
cout<<ia<<endl; // 4
cout<<ib<<endl; // 4
return 0;
}
看起来有点诡异。没错snprintf是可以复制超过sizeof(sz)个字符串的。
其实上面的snprintf的用法都不是一般用法!
常规用法
char c[3];
int ic = snprint(sz, sizeof(sz), "%s", "abcd");
cout<<sz<<endl; // ab
cout<<ic<<endl; // 4
这才是一般的用法。但是如果sz的长度太长,比如业务中设置的某个默认常量(MAX_LEN)通常都有1024甚至4096。完全拷贝MAX_LEN-1个字符,则是浪费!
返回值
snprintf的返回值也有trick。他返回的不是实际写入目标的字符个数(sprint是,snprint不是),而是预期要写入的字符个数,也就是不管参数二size十多少,返回值总是,format替换后的字符个数。
char c[3];
int ic = snprint(sz, sizeof(sz), "xyz%s", "abcd");
cout<<sz<<endl; // xyz
cout<<ic<<endl; // 7