首页 > 编程知识 正文

snprintf函数功能,snprintf函数的用法

时间:2023-05-06 10:54:09 阅读:259302 作者:2798

函数原型 include <stdio.h>int snprintf(char *str, size_t size, const char *format, ...);

str: 目的内存空间地址;

size: 最大可用的目的内存空间大小;

format:格式化字符串(类似printf);

... : 可选参数,与format中的占位符相关(类似printf).

函数功能

该函数可以将不同的内容(ex. int)按照期望的既定格式打印成字符串,并保存到buffer中。

比如需要将十进制数 20 转换为两bytes十六进制字符串的时候,可以使用该函数实现。

int ret;char hex[10];ret = snprintf(hex, sizeof(hex), "0X%04X", 20);

"0X%04X" 表示会先加上0X前缀,通常用来表示是十六进制;后面%04X是指按大写十六进制打印,且需要占据4位字符的宽度,不够4位时补0。所以最终的字符串格式会是“0X0014”。

特别注意

1. 无论何时一定会在字符串末尾添加'' 字符串结束符。

当字符串长度小于size时,会直接在字符串的末尾添加'';当字符串长度等于size时,会取前size-1个字符,并在末尾添加‘’(即:加上''后,一共size个字符);当字符串长度大于size时,只取前size-1个字符,并在末尾添加''(即:加上''一共size个字符);

综上:snprintf不仅一定会自动在字符串末尾添加'',而且一定会尊重指定长度size的大小,不会超过该长度(算上自动在末尾增加的'')。所以从这一点来讲,使用snprintf是相对比较安全的,不用担心会出现overflow的情况。 

 NOTE:这一点上,snprintf与strncpy是有区别的。strncpy虽然也会指定目的内存的大小,但是当源字符串长度大于指定的内存大小时,strncpy虽然在达到指定大小后会停止copy,但是并不会在末尾自动添加''。这样,在访问字符串时,有可能出现overflow的情况,因为末尾没有字符串结束符''。

思考:

(1)当目的内存实际长度为N1,但是在使用snprintf时指定的实际size(第二个参数)为N2, 且N2<N1,可能会出现什么情况?

(2)如果N2>N1,又可能出现什么情况?

2. 特别小心返回值。

当出现错误时,会返回负值;当字符串长度小于size时,返回打印到目的内存的实际字符串长度(不包括'');当字符串长度大于等于size时,尽管字符串会被截断(只有size-1个字符串被打印到目的内存),但是返回值却会返回源字符串的实际长度(即假设目的内存无限大,总是能写下源字符串)。

综上:snprintf的返回值可能大于或等于指定的size,这时候说明目的内存不够大,源字符串被截断,需要小心处理,这是否是期望发生的情形。

NOTE:有一些写法会利用snprintf的这个特点来确定合适的目的内存大小,例如:

const char *fmt = "sqrt(2) = %f";char * buf;int sz = snprintf(NULL, 0, fmt, sqrt(2));buf = (char *)malloc(sz+1); // +1 for append ''snprintf(buf, sz+1, fmt, sqrt(2));  实践

在实际使用snprintf函数时,应该根据自己的实际需求,来判断如何合理的使用。

通常的用法会类似如下。

include <stdio.h>include <stdlib.h>#define BUF_LEN 20char buf[BUF_LEN];int year = 2019;int month = 12;int day = 13;int ret;ret = snprintf(buf, sizeof(buf), "%d-%02d-%02d", year, month, day);if(ret <0) { // error handling} else if(ret >= sizeof(buf)) { // buffer isn't enough, error handling} else { // expected case} 更进一步

snprintf是一个在C99才被加入如标准的函数,原来的各个编译器都有自己的实现,至少.NET2003编译器还要是使用_snprintf这样的函数名称。而这些编译器间都有差异,而且Glibc库又有自己的不同的实现。如果使用一些比较旧的编译器或者不同平台的编译器,你会发现,如果传递的buf的长度不够的情况下,有可能null-terminator都没有加入,那么你使用的时候还是可能溢出,而且返回值的判断在不同的平台也可能不一样。

所以如果你想编一个可以跨平台的安全且正确的snprintf,应该怎么做呢?

以下只是一个可能的参考。

#define MAX_LEN 32char buffer[MAX_LEN];char* source = "xxxxxxx";size_t buf_len = sizeof(buffer) - 1;int len = snprintf(buffer, buf_len, "%s", source); if ((len < 0) || (len > max_len)) { // error handling .... printf("error or overflow!n"); } else { // expected case buffer[max_len] = 0; }

 

参考文章:

[1] https://linux.die.net/man/3/snprintf

[2] http://joequery.me/code/snprintf-c/

[3] https://cloud.tencent.com/developer/article/1546579

[4] https://cloud.tencent.com/developer/article/1021143

 

 

 

 

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。