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; // 8cout<<strlen(str.c_str())<<endl; // 4// str.size() 等于 str.length()cout<<str.size()<<endl; // 4int ia = snprintf(sz, sizeof(str.c_str()), "%s", str.c_str());cout<<sz<<endl; // abcdcout<<sizeof(sz)<<endl; // 100int ib = snprintf(sz, strlen(str.c_str()), "%s", str.c_str());cout<<sz<<endl; // abccout<<ia<<endl; // 4cout<<ib<<endl; // 4return 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; // 3int ia = snprintf(sz, sizeof(str.c_str()), "%s", str.c_str());cout<<sz<<endl; // abcdcout<<sizeof(sz)<<endl; // 3cout<<strlen(sz)<<endl; // 4int ib = snprintf(sz, strlen(str.c_str()), "%s", str.c_str());cout<<sz<<endl; // abccout<<ia<<endl; // 4cout<<ib<<endl; // 4return 0;}
看起来有点诡异。没错snprintf是可以复制超过sizeof(sz)个字符串的。
其实上面的snprintf的用法都不是一般用法!
常规用法
char c[3];int ic = snprint(sz, sizeof(sz), "%s", "abcd");cout<<sz<<endl; // abcout<<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; // xyzcout<<ic<<endl; // 7
