vfprintf
Defined in header <stdio.h>  |   |   | 
|---|---|---|
  | (1)  |   | 
int vprintf( const char *format, va_list vlist );  | (until C99)  | |
int vprintf( const char *restrict format, va_list vlist );  | (since C99)  | |
  | (2)  |   | 
int vfprintf( FILE *stream, const char *format, va_list vlist );  | (until C99)  | |
int vfprintf( FILE *restrict stream, const char *restrict format, va_list vlist );  | (since C99)  | |
  | (3)  |   | 
int vsprintf( char *buffer, const char *format, va_list vlist );  | (until C99)  | |
int vsprintf( char *restrict buffer, const char *restrict format, va_list vlist );  | (since C99)  | |
int vsnprintf( char *restrict buffer, int bufsz, const char *restrict format, va_list vlist );  | (4)  | (since C99)  | 
int vprintf_s( const char *restrict format, va_list arg);  | (5)  | (since C11)  | 
int vfprintf_s( FILE *restrict stream, const char *restrict format, va_list arg);  | (6)  | (since C11)  | 
int vsprintf_s( char *restrict buffer, rsize_t bufsz, const char *restrict format, va_list arg);  | (7)  | (since C11)  | 
int vsnprintf_s(char *restrict buffer, rsize_t bufsz, const char * restrict format, va_list arg);  | (8)  | (since C11)  | 
从定义的位置加载数据vlist,将它们转换为等同字符串并将结果写入各种接收器。
1)将结果写入stdout。
2)将结果写入文件流stream。
3)将结果写入字符串buffer。
4)将结果写入字符串buffer。最多的buf_size字符是写入的。结果字符串将以空字符结尾,除非buf_size为零。如果buf_size为零,则不会写入任何内容,并且buffer可能是空指针,但返回值(将写入的字节数)仍然会计算并返回。
5-8)与(1-4)相同,只是在运行时检测到以下错误并调用当前安装的约束处理函数:
- 转换说明符
%n存在于format - 任何对应的参数
%s都是空指针 format或者buffer是空指针bufsz是零或大于RSIZE_MAX- 编码错误出现在任何字符串和字符转换说明符中
 - (
vsprintf_s仅限于),要存储的字符串buffer(包括结尾空值))将被超出bufsz 
  由于所有的边界检查功能,vprintf_s,vfprintf_s,vsprintf_s,和vsnrintf_s仅保证可供如果__STDC_LIB_EXT1__由实现所定义,并且如果用户定义__STDC_WANT_LIB_EXT1__的整数常数1,包括之前<stdio.h>。  
参数
流  | -  | 输出文件流写入  | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
缓冲  | -  | 指向要写入的字符串的指针  | ||||||||||
bufsz  | -  | 最多bufsz - 可能会写入1个字符,再加上空终止符  | ||||||||||
格式  | -  | 指向以空字符结尾的字符串的指针,指定如何解释数据。  | ||||||||||
格式字符串由普通的多字节字符(除外%)组成,它们被不变地复制到输出流和转换规范中。每个转换规范具有以下格式:  | ||||||||||||
介绍%人物  | ||||||||||||
(可选)一个或多个修改转换行为的标志:  | ||||||||||||
-:转换的结果在字段内左对齐(默认情况下它是右对齐的)  | ||||||||||||
+:带符号转换的符号总是预设为转换结果的前缀(默认情况下结果前面为减号,仅当它为负值时)  | ||||||||||||
空格:如果签名转换的结果不是以符号字符开头,或者是空的,则空格会预设为结果。如果+标志存在,它将被忽略。  | ||||||||||||
#:执行转换的替代形式。请参阅下表以了解确切的效果,否则行为未定义。  | ||||||||||||
0:对于整数和浮点数转换,前导零用于填充字段而不是空格字符。对于整数,如果明确指定了精度,它将被忽略。对于使用此标志的其他转换会导致未定义的行为。如果-标志存在,它将被忽略。  | ||||||||||||
(可选)整数值或*指定最小字段宽度。如果需要,结果会填充空格字符(默认情况下),右侧对齐时填充空白字符,左侧填充右侧填充。在使用的情况下*,宽度由类型的附加参数指定int。如果参数的值是负数,则结果是-指定的标志和正的字段宽度。(注意:这是最小宽度:该值从不被截断。)  | ||||||||||||
(可选) .后面跟随整数或者*或者既不指定转换的精度。在使用的情况下*,精度由类型的附加参数指定int。如果这个参数的值是负数,它将被忽略。如果既不使用数字也不*使用,则精度取为零。请参阅下表以了解精确度的确切影响。  | ||||||||||||
(可选) 长度修饰符,用于指定参数的大小  | ||||||||||||
转换格式说明符  | ||||||||||||
以下格式说明符可用:  | ||||||||||||
转换  | 说明  | 参数类型  | ||||||||||
说明符  | ||||||||||||
长度修饰符  | hh  | h  | (没有)  | l  | ll  | j  | z  | t  | L  | |||
(C99)。  | (C99)。  | (C99)。  | (C99)。  | (C99)。  | ||||||||
%  | 写文字%。完整的转换规范必须是%%。  | N / A  | N / A  | N / A  | N / A  | N / A  | N / A  | N / A  | N / A  | N / A  | ||
c  | 写一个字符。  | N / A  | N / A  | int  | wint_t  | N / A  | N / A  | N / A  | N / A  | N / A  | ||
该论点首先转换为unsigned char。如果使用了l修饰符,则首先将参数转换为字符串,就像通过具有参数的%ls一样wchar_t[2]。  | ||||||||||||
s  | 写入一个字符串  | N / A  | N / A  | char*  | wchar_t*  | N / A  | N / A  | N / A  | N / A  | N / A  | ||
参数必须是指向字符数组的初始元素的指针。Precision指定要写入的最大字节数。如果未指定Precision,则将每个字节写入并不包括第一个空终止符。如果使用了l说明符,则参数必须是指向数组初始元素的指针wchar_t,它将转换为char数组,就像通过调用wcrtomb具有零初始化转换状态一样。  | ||||||||||||
d  | 将有符号整数转换为十进制表示形式[ - ] dddd。  | signed char  | short  | int  | long  | long long  | intmax_t  | 签 size_t  | ptrdiff_t  | N / A  | ||
i  | 精度指定出现的最小位数。默认的精度是1。  | |||||||||||
如果转换后的值和精度都是0没有字符的转换结果。  | ||||||||||||
o  | 将无符号整数转换为八进制表示oooo。  | unsigned char  | unsigned short  | unsigned int  | unsigned long  | unsigned long long  | uintmax_t  | size_t  | 未签名的版本 ptrdiff_t  | N / A  | ||
精度指定出现的最小位数。默认的精度是1。如果转换后的值和精度都是0没有字符的转换结果。在替代实现中,如果需要,可以增加精度以写入一个前导零。在这种情况下,如果转换后的值和精度都是0,0写入单个。  | ||||||||||||
x  | 将无符号整数转换为十六进制表示hhhh。  | N / A  | ||||||||||
X  | 使用x转换字母abcdef。  | |||||||||||
使用X转换字母ABCDEF。  | ||||||||||||
精度指定出现的最小位数。默认的精度是1。如果转换后的值和精度都是0没有字符的转换结果。在替代实现中, 0x或者0X如果转换后的值不为零,则将其作为结果的前缀。  | ||||||||||||
u  | 将无符号整数转换为十进制表示形式dddd。  | N / A  | ||||||||||
精度指定出现的最小位数。默认的精度是1。如果转换后的值和精度都是0没有字符的转换结果。  | ||||||||||||
f  | 将浮点数转换为样式[ - ] ddd.ddd中的十进制表示法。  | N / A  | N / A  | double  | double(C99)  | N / A  | N / A  | N / A  | N / A  | long double  | ||
F  | 精度指定小数点后面出现的最小位数。默认的精度是6。在替代实现中,即使没有数字跟随,小数点字符也会被写入。对于无穷大和非数字转换风格,请参阅注释。  | |||||||||||
e  | 将浮点数转换为十进制指数符号。  | N / A  | N / A  | N / A  | N / A  | N / A  | N / A  | |||||
E  | 对于e转换样式,使用[ - ] d.ddd e±dd。  | |||||||||||
对于E转换样式,使用[ - ] d.ddd E±dd。  | ||||||||||||
指数至少包含两位数字,只有在必要时才使用更多数字。如果值是0,指数也是0。精度指定小数点后面出现的最小位数。默认的精度是6。在替代实现中,即使没有数字跟随,小数点字符也会被写入。对于无穷大和非数字转换风格,请参阅注释。  | ||||||||||||
a  | 将浮点数转换为十六进制指数表示法。  | N / A  | N / A  | N / A  | N / A  | N / A  | N / A  | |||||
A  | 对于a转换样式,使用[ - ] 0xh.hhh p±d。  | |||||||||||
(C99)。  | 对于A转换样式,使用[ - ] 0Xh.hhh P±d。如果参数不是标准化的浮点值,则  | |||||||||||
第一个十六进制数字是0。如果值是0,指数也是0。精度指定小数点后面出现的最小位数。默认精度足以精确表示值。在替代实现中,即使没有数字跟随,小数点字符也会被写入。对于无穷大和非数字转换风格,请参阅注释。  | ||||||||||||
g  | 根据值和精度将浮点数转换为十进制或十进制指数符号。  | N / A  | N / A  | N / A  | N / A  | N / A  | N / A  | |||||
G  | 对于g风格转换的转换与风格e或f将被执行。  | |||||||||||
对于G风格转换的转换与风格E或F将被执行。  | ||||||||||||
让P等于精度如果非零,6如果没有指定精度,或者1如果精度是0。然后,如果具有样式的转换E将具有以下指数X:  | ||||||||||||
如果P> X≥-4,转换是用式f或F和精度P - 1 - X。  | ||||||||||||
否则,转换采用样式e或E精度P - 1。  | ||||||||||||
除非请求替代表示,否则尾随零将被删除,如果没有剩余小数部分,小数点字符也会被删除。对于无穷大和非数字转换风格,请参阅注释。  | ||||||||||||
n  | 将此调用到目前为止写入的字符数返回给该函数。  | signed char*  | short*  | int*  | long*  | long long*  | intmax_t*  | 签 size_t*  | ptrdiff_t*  | N / A  | ||
结果写入参数指向的值。规范可能不包含任何标志,字段宽度或精度。  | ||||||||||||
p  | 写一个实现定义的字符序列来定义一个指针。  | N / A  | N / A  | void*  | N / A  | N / A  | N / A  | N / A  | N / A  | N / A  | ||
浮点转换函数将无穷大转换为inf或infinity。使用哪一个是实现定义的。  | ||||||||||||
非数字转换为nan或。使用哪一个是实现定义的。nan(char_sequence)  | ||||||||||||
该转换F,E,G,A输出INF,INFINITY,NAN来代替。  | ||||||||||||
即使%c需要int参数,通过char调用可变参数函数时发生的整数提升也是安全的。  | ||||||||||||
对于固定宽度的字符类型(正确的转换规格int8_t,等等)都在头中定义<inttypes.h>还(虽然PRIdMAX,PRIuMAX等是同义词%jd,%ju等)。  | ||||||||||||
内存写入转换说明符%n是安全漏洞的常见目标,其中格式字符串取决于用户输入,并且不受边界检查printf_s函数族的支持。  | ||||||||||||
每个转换说明符的操作之后都有一个序列点 ; 这允许将多个%n结果存储在相同的变量中,或者作为边缘情况,%n在相同的调用中打印由较早修改的字符串。  | ||||||||||||
如果转换规范无效,则行为未定义。  | ||||||||||||
VLIST  | -  | 包含要打印的数据的变量参数列表  | ||||||||||
- 介绍
%字符 - (可选)一个或多个修改转换行为的标志: 
-:转换的结果在字段内左对齐(默认情况下它是右对齐的)+:带符号转换的符号总是预设为转换结果的前缀(默认情况下结果前面为减号,仅当它为负值时)- 空格:如果签名转换的结果不是以符号字符开头,或者是空的,则空格会预设为结果。如果
+存在标志,则忽略它。 #:执行转换的替代形式。请参阅下表以了解确切的效果,否则行为未定义。0:对于整数和浮点数转换,前导零用于填充字段而不是空格字符。对于整数,如果明确指定了精度,它将被忽略。对于使用此标志的其他转换会导致未定义的行为。如果-存在标志,则忽略它。
 - (可选)整数值或
*指定最小字段宽度。如果需要,结果会填充空格字符(默认情况下),右侧对齐时填充空白字符,左侧填充右侧填充。在使用的情况下*,宽度由类型的附加参数指定int。如果参数的值是负数,则结果是-指定的标志和正的字段宽度。(注意:这是最小宽度:该值从不被截断。)- (可选)
.后面跟随整数或者*或者既不指定转换的精度。在使用的情况下*,精度由类型的附加参数指定int。如果这个参数的值是负数,它将被忽略。如果既不使用数字也不*使用,则精度取为零。请参阅下表以了解精确度的确切影响。 - (可选)长度修饰符,用于指定参数的大小
 - 转换格式说明符
 
 - (可选)
 
以下格式说明符可用:
Conversion说明符说明参数类型长度修饰符    hh(C99)。
   h   (none)   l   ll (C99).
   j (C99).
   z (C99).
   t (C99).
 L %   写文字%。完整的转换规范必须是%%。N / AN / AN / AN / AN / AN / AN / AN / AN / A      c    写入单个字符。该论点首先转换为unsigned char。如果使用了l修饰符,则首先将参数转换为字符串,就像通过具有参数的%ls一样wchar_t[2]。
   N/A   N/A   int
   wint_t
   N / AN / AN / AN / AN / A      s    写入字符串参数必须是指向字符数组的初始元素的指针。Precision指定要写入的最大字节数。如果未指定Precision,则将每个字节写入并不包括第一个空终止符。如果使用了l说明符,则参数必须是指向数组初始元素的指针wchar_t,它将转换为char数组,就像通过调用wcrtomb具有零初始化转换状态一样。
   N/A   N/A   char*
   wchar_t*
   N/A   N/A   N/A   N/A   N/A     d
 i   将有符号的整数转换为十进制表示形式-dddd。  精度指定出现的最小位数。默认的精度是1。
如果转换后的值和精度都是0没有字符的转换结果。
   signed char
   short
   int
   long
   long long
   intmax_t
   signed size_t 
   ptrdiff_t
   N / A      o   将无符号整数转换为八进制表示oooo。  精度指定出现的最小位数。默认的精度是1。如果转换后的值和精度都是0没有字符的转换结果。在替代实现中,如果需要,可以增加精度以写入一个前导零。在这种情况下,如果转换值和精度都是0,0写入单个。
   unsigned char
   unsigned short
   unsigned int
   unsigned long
   unsigned long long
   uintmax_t
   size_t
   未签名的版本 ptrdiff_t 
   N/A     x
 X   将无符号整数转换为十六进制表示 hhhh。使用x转换字母abcdef。
使用X转换字母ABCDEF。
 精度指定出现的最小位数。默认的精度是1。如果转换后的值和精度都是0没有字符的转换结果。在替代实现中, 0x或者0X如果转换后的值不为零,则将其作为结果的前缀。
   N / A      u   将无符号整数转换为十进制表示形式dddd。  精度指定出现的最小位数。默认的精度是1。如果转换后的值和精度都是0没有字符的转换结果。
   N/A     f
 F   将浮点数转换为样式-ddd.ddd中的小数表示法。  精度指定小数点后面出现的最小位数。默认的精度是6。在替代实现中,即使没有数字跟随,小数点字符也会被写入。对于无穷大和非数字转换风格,请参阅注释。
   N/A   N/A   double
`double` (C99)    N/A   N/A   N/A   N/A   long double
 `e`  E   将浮点数转换为十进制指数符号。对于e转换样式,使用-d.ddd e±dd。
对于E转换样式,使用-d.ddd E±dd。
指数至少包含两位数字,只有在必要时才使用更多数字。如果值是0,指数也是0。精度指定小数点后面出现的最小位数。默认的精度是6。在替代实现中,即使没有数字跟随,小数点字符也会被写入。对于无穷大和非数字转换风格,请参阅注释。
   N/A   N/A   N/A   N/A   N/A   N/A     a 
 A (C99).
   将浮点数转换为十六进制指数表示法。对于a转换样式- 使用0xh.hhh p±d。
对于A转换样式- 使用0Xh.hhh P±d。
0如果参数不是标准化的浮点值,则第一个十六进制数字是。如果值是0,指数也是0。精度指定小数点后面出现的最小位数。默认精度足以精确表示值。在替代实现中,即使没有数字跟随,小数点字符也会被写入。对于无穷大和非数字转换风格,请参阅注释。
   N/A   N/A   N/A   N/A   N/A   N/A     g 
 G根据值和精度 将浮点数转换为十进制或十进制指数符号。对于风格转换的转换与风格或将被执行。gef
对于G风格转换的转换与风格E或F将被执行。
让P等于精度如果非零,6如果没有指定精度,或者1如果精度是0。然后,如果具有样式的转换E将具有以下指数X:
- 如果P> X≥-4,转换是用式
f或F和精度P - 1 - X。 - 否则,转换采用样式
e或E精度P - 1。 
除非请求替代表示,否则尾随零将被删除,如果没有剩余小数部分,小数点字符也会被删除。对于无穷大和非数字转换风格,请参阅注释。
   不适用/不适用/不适用/不适用/      n   返回此函数迄今为止写入的字符数。结果写入参数指向的值。规范可能不包含任何标志,字段宽度或精度。
   signed char*
   short*
   int*
   long*
   long long*
   intmax_t*
   signed size_t* 
   ptrdiff_t*
   N / A      p   写入一个实现定义的字符序列来定义一个指针。不适用不适用不适用不适用不适用不适用    void*   浮点转换函数将无穷大转换为inf或infinity。使用哪一个是实现定义的。
非数字转换为nan或。使用哪一个是实现定义的。nan(char_sequence)
转换F,E,G,A输出INF,INFINITY,NAN来代替。
即使%c需要int参数,通过char调用可变参数函数时发生的整数提升也是安全的。
对于固定宽度的字符类型(正确的转换规格int8_t<inttypes.h>还(虽然,等等)都在头定义PRIdMAX,PRIuMAX等是同义词%jd,%ju等)。
内存写入转换说明符%n是安全漏洞的常见目标,其中格式字符串取决于用户输入,并且不受边界检查printf_s函数族的支持。
每个转换说明符的操作之后都有一个序列点; 这允许将多个%n结果存储在相同的变量中,或者作为边缘情况,%n在同一个调用中打印由较早修改的字符串。
如果转换规范无效,则行为未定义。
 vlist   -   variable argument list containing the data to print   返回值
1-3)如果发生错误,则写入的字符数如果成功或为负值。
4)如果发生错误,则成功写入字符数或写入负值。如果由于buf_size限制而导致结果字符串被截断,则函数将返回如果未施加该限制的情况下将被写入的字符总数(不包括终止空字节)。
5,6)传输到输出流的字符数或负值(如果发生输出错误,运行时间约束违规错误或编码错误)。
7)写入的字符数buffer,不包括空字符(只要buffer不是空指针,bufsz并且不为零且不大于RSIZE_MAX),则不计入空字符,或者在运行时约束违规时为零,编码错误为负值
8)不包括终止空字符的字符数(只要buffer不是空指针并且bufsz不为零且不大于RSIZE_MAX),buffer如果bufsz被忽略,将被写入的字符数或者如果运行时约束违规或编码错误发生
笔记
所有这些函数va_arg至少调用一次,arg返回后的值是不确定的。这些函数不会调用va_end,并且它必须由调用者完成。
vsnprintf_s不像vsprintf_s,会截断结果以适应指向的数组buffer。
例
#include <stdio.h>
#include <stdarg.h>
#include <time.h>
 
void debug_log(const char *fmt, ...)
{
    struct timespec ts;
    timespec_get(&ts, TIME_UTC);
    char time_buf[100];
    size_t rc = strftime(time_buf, sizeof time_buf, "%D %T", gmtime(&ts.tv_sec));
    snprintf(time_buf + rc, sizeof time_buf - rc, ".%06ld UTC", ts.tv_nsec / 1000);
 
    va_list args1;
    va_start(args1, fmt);
    va_list args2;
    va_copy(args2, args1);
    char buf[1+vsnprintf(NULL, 0, fmt, args1)];
    va_end(args1);
    vsnprintf(buf, sizeof buf, fmt, args2);
    va_end(args2);
 
    printf("%s [debug]: %s\n", time_buf, buf);
}
 
int main(void)
{
    debug_log("Logging, %d, %d, %d", 1, 2, 3);
}可能的输出:
02/20/15 21:58:09.072683 UTC [debug]: Logging, 1, 2, 3参考
- C11 standard (ISO/IEC 9899:2011): 
- 7.21.6.8 The vfprintf function (p: 326-327)
 - 7.21.6.10 The vprintf function (p: 328)
 - 7.21.6.12 The vsnprintf function (p: 329)
 - 7.21.6.13 The vsprintf function (p: 329)
 - K.3.5.3.8 The vfprintf_s function (p: 597)
 - K.3.5.3.10 The vprintf_s function (p: 598-599)
 - K.3.5.3.12 The vsnprintf_s function (p: 600)
 - K.3.5.3.13 The vsprintf_s function (p: 601)
 
 - C99 standard (ISO/IEC 9899:1999): 
- 7.19.6.8 The vfprintf function (p: 292)
 - 7.19.6.10 The vprintf function (p: 293)
 - 7.19.6.12 The vsnprintf function (p: 294)
 - 7.19.6.13 The vsprintf function (p: 295)
 
 - C89/C90 standard (ISO/IEC 9899:1990): 
- 4.9.6.7 The vfprintf function
 - 4.9.6.8 The vprintf function
 - 4.9.6.9 The vsprintf function
 
 
本文档系腾讯云开发者社区成员共同维护,如有问题请联系 cloudcommunity@tencent.com

