当前位置: C语言 -- 标准库 -- <stdio.h> -- vprintf

vprintf函数


概要:
#include <stdarg.h>
#include <stdio.h>
int vprintf(const char * restrict format,
      va_list arg);

描述:

vprintf函数等价于printf函数,区别在于vprintf函数使用va_list类型参数arg替换可变参数列表。参数arg应已经使用宏va_start初始化(以及后续可能调用宏va_arg。);但vprintf函数不会调用va_end宏。

该函数将输出写入标准输出流,参数format指向的字符串指定后续参数如何转换为输出。

格式序列由0至多个指令构成,函数调用时按顺序执行格式序列中的指令,执行到格式序列末尾时,函数将返回。

如果格式序列对应的参数数量不足,函数行为是未定义的;如果参数数量过多,多余参数会被评估,否则将被忽略。

ISO/IEC 9899:2018标准定义了该函数的安全版本vprintf_s函数。


参数:
const char * restrict format

char类型指针,指向格式字符串,格式字符串应为多字节字符序列,其开始和结束都为初始移位状态(initial shift state)。构成格式序列的指令分为以下两种情况:

- 由普通多字节字符(字符%除外)构成的指令。

普通多字节字符不作任何改变写入标准输出流。


- 由转换说明构成的指令。

每个转换说明都会获取0至多个后续参数,并根据相应的转换说明符(如果适用)对其进行转换,然后将结果写入标准输出流。


转换说明遵循以下格式:

%标记符opt字段宽度符opt精度符opt长度修饰符opt转换说明符

其中带opt的都是可选的。


1、标记符及其意义

标记符 描述
-

转换结果在字段内左对齐。默认情况下是右对齐。

+

有符号的转换结果总是以+号或者-号开头。默认情况下正值前没有+号。

空格

如果一个有符号转换的首字符不是符号,或者一个有符号转换结果没有字符,将在结果前添加空格。如果在标记符中同时出现空格标记符和+标记符,空格标记符将被忽略。

#

对于o转换,当且仅在必要时,会增加精度以强制结果的第一位数字为0;如果值和精度均为0,则输出单个0。对于x(或者X)转换,将给非0结果前置0x(或者0X)。对于aAeEfFgG转换,结果将转换为带有小数点的浮点数,即使小数点后没有数字(通常小数点字符仅在其后有数字时才会出现在这些转换结果中。)。对于g(或者G)转换,尾随0会保留。对于其它形式转换,其行为是未定义的。

0

对于diouxXaAeEfFgG转换,前导0(跟在符号或者基数之后)将代替空格填充字段,转换无穷大或者非数值除外。如果在标记符中同时出现0标记符和-标记符,0标记符将被忽略。对于diouxX转换,如果指定了精度,0标记符将被忽略。对于其它形式转换,其行为是未定义的。

如果存在多个标记符,ISO/IEC 9899:2018标准并未指定标记符的先后顺序。


2、字段宽度符及其意义

字段宽度符 描述
数字

该数字为大于0的十进制整数,表示最小字段宽度。

*

该字符表示最小字段宽度,该字符并未直接指定字段宽度,需要在转换参数前有一个额外整值参数来指定字段宽度,例如:printf("%*d", width, value);,其中参数width指定字段宽度。如果width是负整数,转换结果是左对齐的。

如果字段宽度为负值,就相当于使用其绝对值作为字段宽度,-字符作为标记符。

如果转换值含有的字符数小于字段宽度,默认情况下在转换值左边填充空格;如果转换值含有的字符数大于等于字段宽度,转换值正常输出。


3、精度符及其意义

精度符 描述
.数字

该数字为十进制整数。

.*

该字符未直接指定精度,需要在转换参数前有一个额外整值参数指定精度,例如:printf("%.*f", precision, value);,其中参数precision指定精度。

对于diouxX转换,精度符表示出现的最小位数。对于aAeEfF转换,精度符表示小数点后出现的位数。对于gG转换,精度符表示最大有效位数。对于s转换,精度符表示写入的最大字节数。如果只指定.字符,精度值为0

如果精度符与除上面指定的转换说明符一起使用,其行为是未定义的。


4、长度修饰符及其意义

长度修饰符 描述
hh

对于diouxX转换说明符,该字符用于signed char或者unsigned char类型参数(参数会被整数提升,但在输出前参数值应转换为signed char或者unsigned char类型。)。对于n转换说明符,该字符用于signed char类型指针。

h

对于diouxX转换说明符,该字符用于short int或者unsigned short int类型参数(参数会被整数提升,但在输出前参数值应转换为short int或者unsigned short int类型。)。对于n转换说明符,该字符用于short int类型指针。

l

对于diouxX转换说明符,该字符用于long int或者unsigned long int类型参数。对于n转换说明符,该字符用于long int类型指针。对于c转换说明符,该字符用于wint_t类型参数。对于s转换说明符,该字符用于wchar_t类型指针。对于aAeEfFgG转换说明符,该字符不起作用。

ll

对于diouxX转换说明符,该字符用于long long int或者unsigned long long int类型参数。对于n转换说明符,该字符用于long long int类型指针。

j

对于diouxX转换说明符,该字符用于intmax_t或者uintmax_t类型参数。对于n转换说明符,该字符用于intmax_t类型指针。

z

对于diouxX转换说明符,该字符用于size_t或者对应的有符号整数类型参数。对于n转换说明符,该字符用于对应size_t的有符号整数类型指针。

t

对于diouxX转换说明符,该字符用于ptrdiff_t或者对应的无符号整数类型参数。对于n转换说明符,该字符用于ptrdiff_t类型指针。

L

对于aAeEfFgG转换说明符,该字符用于long double类型参数。

如果长度修饰符与除上面指定的转换说明符一起使用,其行为是未定义的。


5、转换说明符及其意义

转换说明符 描述
d,i

int类型参数转换为有符号十进制整数。精度指定转换结果的最小位数。如果转换结果的位数小于精度值,将添加前导0。默认精度为1。精度为00值转换结果没有字符。(:转换说明符di对于格式化输出函数(例如:vprintf函数)是没有区别的;但对于格式化输入函数(例如:vscanf函数)两者是有区别的。)

o,u,x,X

unsigned int类型参数转换为无符号的八进制整数(o)、十进制整数(u)或者十六进制整数(x或者X)。小写字母abcdef用作x转换;大写字母ABCDEF用作X转换。精度指定转换结果的最小位数。如果转换结果的位数小于精度值,将添加前导0。默认精度为1。精度为00值转换结果没有字符。

f,F

double类型参数转换为[-]ddd.ddd形式的十进制浮点数,其中小数点后位数等于精度值。如果没有指定精度,默认精度为6。如果精度为0,并且没有使用#标记符,将不会出现小数点。如果转换结果中出现小数点,小数点前至少有一位数。转换结果会被舍入到合适的位数。

如果double类型参数表示无穷大,是转换成[-]inf形式还是转换成[-]infinity形式将由实现定义。如果double类型参数表示非数值,是转换成[-]nan形式还是转换成[-]nan(n-char-sequence)形式,以及n-char-sequence的含义将由实现定义。f转换说明符对应infinfinity或者nanF转换说明符对应INFINFINITY或者NAN。(:当用于无穷大和非数值时,-+和空格标记符具有其通常的含义;但#0标记符没有影响。)

e,E

double类型参数转换为科学计数法形式([-]d.ddde±dd),其中小数点前有一位数,如果参数是非0值,该数也是非0值;小数点后位数等于精度值。如果没有指定精度,默认精度为6。如果精度为0,并且没有使用#标记符,将不会出现小数点。转换结果会被舍入到合适的位数。e转换说明符对应指数为eE转换说明符对应指数为E。指数位数至少为2位;并且仅包含表示指数所需的更多位数。如果参数值为0,指数为0

如果double类型参数表示无穷大,是转换成[-]inf形式还是转换成[-]infinity形式将由实现定义。如果double类型参数表示非数值,是转换成[-]nan形式还是转换成[-]nan(n-char-sequence)形式,以及n-char-sequence的含义将由实现定义。e转换说明符对应infinfinity或者nanE转换说明符对应INFINFINITY或者NAN。(:当用于无穷大和非数值时,-+和空格标记符具有其通常的含义;但#0标记符没有影响。)

g,G

double类型参数表示的浮点数是按e转换说明符还是按f转换说明符进行转换(对于G转换说明符,对应的是E转换说明符和F转换说明符。)取决于转换值和精度。声明一个变量P,如果精度值为非0值,P等于精度值;如果省略精度,P等于6;如果精度值为0P等于1。如果转换按E转换说明符进行转换,将有一个指数X

- 如果P>X≥-4,转换将按f(或者F)转换说明符进行转换,并且精度值为P-(X+1)

- 否则转换将按e(或者E)转换说明符进行转换,并且精度值为P-1

如果未使用#标记符,结果的小数部分将删除所有尾随0,并且如果不存在小数部分,将删除小数点。

如果double类型参数表示无穷大,是转换成[-]inf形式还是转换成[-]infinity形式将由实现定义。如果double类型参数表示非数值,是转换成[-]nan形式还是转换成[-]nan(n-char-sequence)形式,以及n-char-sequence的含义将由实现定义。g转换说明符对应infinfinity或者nanG转换说明符对应INFINFINITY或者NAN。(:当用于无穷大和非数值时,-+和空格标记符具有其通常的含义;但#0标记符没有影响。)

a,A

double类型参数表示的浮点数将转换成[-]0xh.hhhhp±d形式,其中小数点前有1位十六进制数(如果参数是规格化浮点数(normalized floating-point number),该十六进制数为非0值;否则其值是不确定的。);小数点后十六进制数的位数与精度值相同。如果没有指定精度并且FLT_RADIX2的幂,那么精度足以精确表示转换值。如果没有指定精度并且FLT_RADIX不是2的幂,那么精度足以区分double类型的值,但尾随0可能会被省略。如果精度为0,并且没有使用#标记符,将不会出现小数点。字母abcdef用于a转换;字母ABCDEF用于A转换。a转换的转换结果使用xpA转换的转换结果使用XP。指数位数至少为1位;并且仅包含表示2的十进制指数所需的更多位数。如果值为0,指数为0

如果double类型参数表示无穷大,是转换成[-]inf形式还是转换成[-]infinity形式将由实现定义。如果double类型参数表示非数值,是转换成[-]nan形式还是转换成[-]nan(n-char-sequence)形式,以及n-char-sequence的含义将由实现定义。a转换说明符对应infinfinity或者nanA转换说明符对应INFINFINITY或者NAN。(:当用于无穷大和非数值时,-+和空格标记符具有其通常的含义;但#0标记符没有影响。)

c

如果不存在l长度修饰符,int类型参数将转换为unsigned char类型,并将结果字符写入标准输出流。

如果存在l长度修饰符,wint_t类型参数的转换就像一个未指定精度的ls转换,并且参数指向wchar_t类型的由两个元素构成的数组的初始元素,其中第一个元素为进行lc转换的wint_t类型参数,第二个元素为空宽字符。

s

如果不存在l长度修饰符,参数应为指向字符数组初始元素的指针。数组中的字符将写入标准输出流,直至但不包括终止空字符。如果指定了精度,写入的字符数不超过精度值。如果没有指定精度或者精度值大于数组长度,数组应包含空字符。

如果存在l长度修饰符,参数应为指向wchar_t类型数组初始元素的指针。数组中的宽字符将转换成多字节字符(每个宽字符就像调用wcrtomb函数一样转换成多字节字符,第一个宽字符转换前,将mbstate_t对象描述的转换状态初始化为0。),直至并包括终止空宽字符。生成的多字节字符将被写入标准输出流,直至但不包括终止空字符(字节)。如果没有指定精度,数组应包含空宽字符。如果指定精度,写入标准输出流的字节数(包括移位序列,如果存在。)不超过精度值;如果为等于由精度值指定的多字节字符序列长度,数组应包含一个空宽字符,函数需要访问数组后的第一个宽字符。任何情况下都不能向标准输出流写入部分多字节字符。

p

参数应为void类型指针。指针值转换为实现定义的打印字符序列。

n

参数应为一个指向有符号整数的指针,到目前为止通过调用vprintf函数写入到标准输出流的字符数将写入该整数。对于该转换说明符,没有参数被转换,但消耗一个参数。如果转换说明包含标记符、字段宽度符或者精度符,该转换说明符的行为是未定义的。

%

向标准输出流写入一个%字符。没有参数被转换。完整的转换说明为%%


长度修饰符、转换说明符和对应的参数类型如下表所示:

d i u o x X a A e E f F g G c s p n
int unsigned int double int char * void * int *
hh signed char unsigned char signed char *
h short int unsigned short int short int *
l long int unsigned long int wint_t wchar_t * long int *
ll long long int unsigned long long int long long int *
j intmax_t uintmax_t intmax_t *
z size_t size_t size_t *
t ptrdiff_t ptrdiff_t ptrdiff_t *
L long double

该处类型为与size_t类型对应的有符号整数类型。

该处类型为指向与size_t类型对应的有符号整数的指针类型。

该处类型为与ptrdiff_t类型对应的无符号整数类型。


如果转换说明无效,函数行为是未定义的。如果参数不是转换说明所对应的类型,函数行为是未定义的。

任何情况下,不存在的或者较小的字段宽度都不会导致字段被截断;如果转换结果宽于字段宽度,字段会被扩展,以便包含转换结果。

对于a(或者A)转换,如果FLT_RADIX2的幂,转换值准确地舍入为具有指定精度的十六进制浮点数。


va_list arg

va_list类型对象。


返回值:

如果发生输出错误或者编码错误,函数返回一个负值;否则函数返回写入标准输出流的字符数。


范例:
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
/*函数vprintf范例*/

#include <stdarg.h>
#include <stdio.h>

static int count = 0;

void archives(const char *format, ...)
{
    printf("No.%d Archives\n", ++count);

    va_list args;
    va_start(args, format);
    vprintf(format, args);
    va_end(args);

    putchar('\n');
}

int main(void)
{
    archives("Name: %s\n", "Zhangshan");
    archives("Name: %s\nGender: %c\n", "Lisi", 'M');
    archives("Name: %s\nGender: %c\nAge: %d\n", "Wangwu", 'M', 25);

    return 0;
}


输出:

No.1 Archives

Name: Zhangshan

 

No.2 Archives

Name: Lisi

Gender: M

 

No.3 Archives

Name: Wangwu

Gender: M

Age: 25


相关内容:
vfprintf 将输出写入流的函数。
vsnprintf 将限定大小的输出写入数组的函数。
vsprintf 将输出写入数组的函数。