命名空间
变体
操作

vprintf、vfprintf、vsprintf、vsnprintf、vprintf_s、vfprintf_s、vsprintf_s、vsnprintf_s

来自 cppreference.com
< c‎ | io
 
 
文件输入/输出
类型和对象
函数
文件访问
直接输入/输出
非格式化输入/输出
(C95)(C95)
(C95)
(C95)(C95)
(C95)
(C95)
格式化输入
(C99)(C99)(C99)(C11)(C11)(C11)     
格式化输出
vprintfvfprintfvsprintfvsnprintfvprintf_svfprintf_svsprintf_svsnprintf_s
(C99)(C11)(C11)(C11)(C11)
文件定位
错误处理
文件操作
 
定义在头文件 <stdio.h>
(1)
int vprintf( const char* format, va_list vlist );
(直到 C99)
int vprintf( const char* restrict format, va_list vlist );
(自 C99 起)
(2)
int vfprintf( FILE* stream, const char* format, va_list vlist );
(直到 C99)
int vfprintf( FILE* restrict stream, const char* restrict format,
              va_list vlist );
(自 C99 起)
(3)
int vsprintf( char* buffer, const char* format, va_list vlist );
(直到 C99)
int vsprintf( char* restrict buffer, const char* restrict format,
              va_list vlist );
(自 C99 起)
int vsnprintf( char* restrict buffer, size_t bufsz,
               const char* restrict format, va_list vlist );
(4) (自 C99 起)
int vprintf_s( const char* restrict format, va_list vlist );
(5) (自 C11 起)
int vfprintf_s( FILE* restrict stream, const char* restrict format,
                va_list vlist );
(6) (自 C11 起)
int vsprintf_s( char* restrict buffer, rsize_t bufsz,
                const char* restrict format, va_list vlist );
(7) (自 C11 起)
int vsnprintf_s( char* restrict buffer, rsize_t bufsz,
                 const char* restrict format, va_list vlist );
(8) (自 C11 起)

vlist 定义的位置加载数据,将其转换为字符字符串等效项,并将结果写入各种接收器。

1) 将结果写入 stdout
2) 将结果写入文件流 stream
3) 将结果写入字符字符串 buffer
4) 将结果写入字符字符串 buffer。最多写入 bufsz - 1 个字符,加上空终止符。生成的字符字符串将以空字符结尾,除非 bufsz 为零。如果 bufsz 为零,则不会写入任何内容,buffer 可以是空指针,但是返回值(不包括空终止符的要写入的字节数)仍然会计算并返回。
5-8)(1-4) 相同,只是以下错误在运行时会被检测到,并调用当前安装的 约束处理程序 函数
  • 转换说明符 %n 存在于 format
  • 任何与 %s 对应的参数都是空指针
  • formatbuffer 是空指针
  • bufsz 为零或大于 RSIZE_MAX
  • 在任何字符串和字符转换说明符中发生编码错误
  • (仅限于 vsprintf_s),要存储在 buffer 中的字符串(包括尾随空字符)将超过 bufsz
与所有边界检查函数一样,vprintf_svfprintf_svsprintf_svsnprintf_s 只有在实现定义了 __STDC_LIB_EXT1__ 并且用户在包含 <stdio.h> 之前将 __STDC_WANT_LIB_EXT1__ 定义为整数常量 1 时才保证可用。

内容

[编辑] 参数

stream - 要写入的输出文件流
buffer - 指向要写入的字符字符串的指针
bufsz - 最多可以写入 bufsz - 1 个字符,加上空终止符
format - 指向指定如何解释数据的空终止字符字符串的指针
vlist - 包含要打印数据的可变参数列表。

format 字符串由普通字节字符(除了 %)组成,这些字符会原样复制到输出流中,以及转换说明符。每个转换说明符具有以下格式

  • 介绍性 % 字符。
  • (可选) 一个或多个标志,修改转换的行为
  • -:转换结果在字段中左对齐(默认情况下为右对齐)。
  • +:有符号转换的符号始终被附加到转换结果的前面(默认情况下,结果只有在为负数时才在前面加上减号)。
  • 空格:如果带符号转换的结果没有以符号字符开头,或者为空,则在结果前面加上空格。如果存在 + 标志,则会忽略它。
  • #:执行转换的替代形式。有关确切效果,请参阅下表,否则行为未定义。
  • 0:对于整数和浮点数转换,使用前导零填充字段,而不是使用空格字符。对于整数,如果显式指定精度,则会忽略它。对于使用此标志的其他转换,会导致未定义的行为。如果存在 - 标志,则会忽略它。
  • (可选) 整数值或*,指定最小字段宽度。如果需要,结果将在右对齐时用空格字符(默认)填充左侧,或在左对齐时用空格字符填充右侧。当使用*时,宽度由类型为 int 的附加参数指定,该参数出现在要转换的参数之前,以及如果提供精度参数,则出现在精度参数之前。如果参数的值为负数,则会导致指定-标志和正字段宽度(注意:这是最小宽度:值永远不会被截断)。
  • (可选) . 后面跟着整数或*,或者两者都不指定转换的精度。当使用*时,精度由类型为 int 的附加参数指定,该参数出现在要转换的参数之前,但在最小字段宽度参数之后(如果有)。如果此参数的值为负数,则会被忽略。如果既没有使用数字也没有使用*,则精度被视为零。请参阅下面的表格了解精度的具体影响。
  • (可选) 长度修饰符,指定参数的大小(结合转换格式说明符,它指定了对应参数的类型)。
  • 转换格式说明符。

以下格式说明符可用

转换
说明符
解释 预期
参数类型
长度
修饰符
hh

(C99)

h (无) l ll

(C99)

j

(C99)

z

(C99)

t

(C99)

L
% 写入字面量%。完整的转换规范必须是%% N/A N/A N/A N/A N/A N/A N/A N/A N/A
c
写入单个字符

参数首先被转换为 unsigned char。如果使用l修饰符,则参数首先被转换为字符字符串,就好像通过%ls使用 wchar_t[2] 参数一样。

N/A N/A
int
wint_t
N/A N/A N/A N/A N/A
s
写入字符字符串

参数必须是指向字符数组的初始元素的指针。精度指定要写入的最大字节数。如果未指定精度,则写入直到并包括第一个空终止符的所有字节。如果使用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
signed size_t
N/A
o
无符号整数转换为八进制表示oooo

精度指定要显示的最小位数。默认精度为 1。如果转换后的值和精度都为 0,则转换结果为零个字符。在替代实现中,如果需要,精度将增加,以便写入一个前导零。在这种情况下,如果转换后的值和精度都为 0,则会写入单个 0

unsigned char
unsigned short
unsigned int
unsigned long
unsigned long long
ptrdiff_t 的无符号版本
N/A
x
X
无符号整数转换为十六进制表示hhhh

对于x转换,使用字母abcdef
对于X转换,使用字母ABCDEF
精度指定要显示的最小位数。默认精度为 1。如果转换后的值和精度都为 0,则转换结果为零个字符。在替代实现中,如果转换后的值为非零,则会将0x0X作为前缀添加到结果中。

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.ddde±dd
对于E转换样式,使用[-]d.dddE±dd
指数至少包含两位数字,仅在必要时才会使用更多位数。如果值为 0,则指数也为 0精度指定小数点字符后出现的精确位数。默认精度为 6。在替代实现中,即使没有位数跟随,也会写入小数点字符。有关无穷大和非数的转换样式,请参阅注释。

N/A N/A N/A N/A N/A N/A
a
A

(C99)

浮点数转换为十六进制指数表示法。

对于a转换样式,使用[-]0xh.hhhp±d
对于A转换样式,使用[-]0Xh.hhhP±d
如果参数是归一化浮点数,则第一个十六进制数字不是0。如果值为 0,则指数也为 0精度指定十六进制点字符后出现的精确位数。默认精度足以精确表示该值。在替代实现中,即使没有位数跟随,也会写入小数点字符。有关无穷大和非数的转换样式,请参阅注释。

N/A N/A N/A N/A N/A N/A
g
G
根据值和精度,将浮点数转换为十进制或十进制指数表示法。

对于g转换样式,将使用ef样式的转换。
对于G转换样式,将使用EF样式的转换。
P等于精度(如果非零),如果未指定精度则为 6,如果精度为 0则为 1。然后,如果使用E样式的转换将产生指数X

  • 如果P > X ≥ −4,则转换使用fF样式,精度为P − 1 − X
  • 否则,转换使用eE样式,精度为P − 1

除非请求替代表示,否则尾随零将被删除,如果剩余小数部分,则小数点字符也将被删除。有关无穷大和非数的转换样式,请参阅注释。

N/A N/A N/A N/A N/A N/A
n
返回此函数调用中写入的字符数

结果被写入到参数指向的值。规范可能不包含任何标志字段宽度精度



signed char*
short*
int*
long*
long long*
signed size_t*
N/A
p 写入定义指针的实现定义的字符序列。 N/A N/A void* N/A N/A N/A N/A N/A N/A

浮点转换函数将无穷大转换为infinfinity。使用哪一个是实现定义的。

非数被转换为nannan(char_sequence)。使用哪一个是实现定义的。

转换FEGA输出INFINFINITYNAN

即使%c期望int参数,但传递char也是安全的,因为在调用可变参数函数时会发生整数提升。

固定宽度字符类型(int8_t 等)的正确转换规范在头文件 <inttypes.h> 中定义(尽管 PRIdMAXPRIuMAX 等等同于%jd%ju 等)。

内存写入转换说明符 %n 是安全漏洞的常见目标,其中格式字符串依赖于用户输入,并且不受边界检查的printf_s 函数系列的支持。

每个转换说明符操作之后都有一个顺序点;这允许将多个 %n 结果存储在同一个变量中,或者作为一种极端情况,在同一个调用中打印由早期 %n 修改的字符串。

如果转换规范无效,则行为未定义。

[编辑] 返回值

1-3) 如果成功,则写入的字符数;如果发生错误,则为负值。
4) 如果成功,则写入的字符数;如果发生错误,则为负值。如果生成的字符串由于 buf_size 限制而被截断,则函数返回将要写入的字符总数(不包括终止的空字节),如果未施加限制。
5,6) 传输到输出流的字符数,或如果发生输出错误、运行时约束违反错误或编码错误,则为负值。
7) 写入 buffer 的字符数,不包括空字符(只要 buffer 不是空指针并且 bufsz 不为零且不大于 RSIZE_MAX,就会始终写入),或者在运行时约束违反时为零,以及在编码错误时为负值。
8) 不包括终止的空字符(只要 buffer 不是空指针并且 bufsz 不为零且不大于 RSIZE_MAX,就会始终写入)的字符数,如果忽略 bufsz,将写入 buffer,或者如果发生运行时约束违反或编码错误,则为负值。

[编辑] 注释

所有这些函数都至少调用一次 va_arg,返回值后 arg 的值是不确定的。这些函数不调用 va_end,必须由调用方完成。

vsnprintf_svsprintf_s 不同,它会将结果截断以适合由 buffer 指向的数组。

Microsoft CRT 中实现的 vsnprintf_s 不符合 C 标准。Microsoft 的版本在第三个位置有一个额外的参数 size_t count,它包含要写入的最大字符数,不包括空终止符。此参数可能与通过参数 size_t bufsz 提供的缓冲区大小不同。

[编辑] 例子

#include <stdarg.h>
#include <stdio.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

[编辑] 参考文献

  • C23 标准 (ISO/IEC 9899:2024)
  • 7.21.6.8 vfprintf 函数 (p: TBD)
  • 7.21.6.10 vprintf 函数 (p: TBD)
  • 7.21.6.12 vsnprintf 函数 (p: TBD)
  • 7.21.6.13 vsprintf 函数 (p: TBD)
  • K.3.5.3.8 vfprintf_s 函数 (p: TBD)
  • K.3.5.3.10 vprintf_s 函数 (p: TBD)
  • K.3.5.3.12 vsnprintf_s 函数 (p: TBD)
  • K.3.5.3.13 vsprintf_s 函数 (p: TBD)
  • C17 标准 (ISO/IEC 9899:2018)
  • 7.21.6.8 vfprintf 函数 (p: 238)
  • 7.21.6.10 vprintf 函数 (p: 239)
  • 7.21.6.12 vsnprintf 函数 (p: 239-240)
  • 7.21.6.13 vsprintf 函数 (p: 240)
  • K.3.5.3.8 vfprintf_s 函数 (p: 434)
  • K.3.5.3.10 vprintf_s 函数 (p: 435)
  • K.3.5.3.12 vsnprintf_s 函数 (p: 436-437)
  • K.3.5.3.13 vsprintf_s 函数 (p: 437)
  • C11 标准 (ISO/IEC 9899:2011)
  • 7.21.6.8 vfprintf 函数 (p: 326-327)
  • 7.21.6.10 vprintf 函数 (p: 328)
  • 7.21.6.12 vsnprintf 函数 (p: 329)
  • 7.21.6.13 vsprintf 函数 (p: 329)
  • K.3.5.3.8 vfprintf_s 函数 (p: 597)
  • K.3.5.3.10 vprintf_s 函数 (p: 598-599)
  • K.3.5.3.12 vsnprintf_s 函数 (p: 600)
  • K.3.5.3.13 vsprintf_s 函数 (p: 601)
  • C99 标准 (ISO/IEC 9899:1999)
  • 7.19.6.8 vfprintf 函数 (p: 292)
  • 7.19.6.10 vprintf 函数 (p: 293)
  • 7.19.6.12 vsnprintf 函数 (p: 294)
  • 7.19.6.13 vsprintf 函数 (p: 295)
  • C89/C90 标准 (ISO/IEC 9899:1990)
  • 4.9.6.7 vfprintf 函数
  • 4.9.6.8 vprintf 函数
  • 4.9.6.9 vsprintf 函数

[编辑] 另见

使用可变参数列表将格式化的宽字符输出打印到 stdout、文件流
或缓冲区。
(函数) [编辑]
使用可变参数列表将格式化的输出打印到 stdout、文件流或缓冲区。
(函数) [编辑]
使用可变参数列表从 stdin、文件流或缓冲区读取格式化的输入。
使用可变参数列表。
(函数) [编辑]
C++ 文档 for vprintf, vfprintf, vsprintf, vsnprintf