vsprintf_s函数
概要:
#define __STDC_WANT_LIB_EXT1__ 1 #include <stdarg.h> #include <stdio.h> int vsprintf_s(char * restrict s, rsize_t n, const char * restrict format, va_list arg);
描述:
该函数将输出写入参数s指向的数组,最多可以写入(n-1)个字符,并在写入字符末尾添加空字符,但空字符不作为函数返回值的一部分;参数format指向的字符串指定后续参数如何转换为输出。
格式序列由0至多个指令构成,函数调用时按顺序执行格式序列中的指令,执行到格式序列末尾时,函数将返回。
如果格式序列对应的参数数量不足,函数行为是未定义的;如果参数数量过多,多余参数会被评估,否则将被忽略。
如果复制发生在重叠对象之间,函数行为是未定义的。
该函数等价于vsprintf函数,区别在于vsprintf_s函数存在运行约束。
与vsnprintf_s函数不同,如果结果大于参数s指向的数组,vsprintf_s函数将其视为运行约束冲突。
运行约束:
参数s、format不能是空指针。参数n既不能等于0,也不能大于宏RSIZE_MAX。写入参数s指向数组的结果字符数应不大于参数n。转换说明%n不能出现在参数format指向的字符串中;但如果%n不被解释为转换说明,则不会引起运行约束冲突,例如:%%n。与转换说明%s对应的参数不能为空指针。不能发生编码错误。
如果存在运行约束冲突,并且参数s不是空指针,参数n大于0且不大于宏RSIZE_MAX,函数vsprintf_s将s[0]设置为空字符。
参数:
char类型指针,输出字符串将存储在该指针指向的数组中。数组必须足够大,能够容纳输出字符串。
指定写入字符的最大数量,最大数量为(n-1),不包括末尾空字符。
char类型指针,指向格式字符串,格式字符串应为多字节字符序列,其开始和结束都为初始移位状态(initial shift state)。构成格式序列的指令分为以下两种情况:
- 由普通多字节字符(字符%除外)构成的指令。
普通多字节字符不作任何改变写入数组。
- 由转换说明构成的指令。
每个转换说明都会获取0至多个后续参数,并根据相应的转换说明符(如果适用)对其进行转换,然后将结果写入数组。
转换说明遵循以下格式:
%标记符opt字段宽度符opt精度符opt长度修饰符opt转换说明符
其中带opt的都是可选的。
1、标记符及其意义
标记符 | 描述 |
- | 转换结果在字段内左对齐。默认情况下是右对齐。 |
+ | 有符号的转换结果总是以+号或者-号开头。默认情况下正值前没有+号。 |
空格 | 如果一个有符号转换的首字符不是符号,或者一个有符号转换结果没有字符,将在结果前添加空格。如果在标记符中同时出现空格标记符和+标记符,空格标记符将被忽略。 |
# | 对于o转换,当且仅在必要时,会增加精度以强制结果的第一位数字为0;如果值和精度均为0,则输出单个0。对于x(或者X)转换,将给非0结果前置0x(或者0X)。对于a、A、e、E、f、F、g、G转换,结果将转换为带有小数点的浮点数,即使小数点后没有数字(通常小数点字符仅在其后有数字时才会出现在这些转换结果中。)。对于g(或者G)转换,尾随0会保留。对于其它形式转换,其行为是未定义的。 |
0 | 对于d、i、o、u、x、X、a、A、e、E、f、F、g、G转换,前导0(跟在符号或者基数之后)将代替空格填充字段,转换无穷大或者非数值除外。如果在标记符中同时出现0标记符和-标记符,0标记符将被忽略。对于d、i、o、u、x、X转换,如果指定了精度,0标记符将被忽略。对于其它形式转换,其行为是未定义的。 |
如果存在多个标记符,ISO/IEC 9899:2018标准并未指定标记符的先后顺序。
2、字段宽度符及其意义
字段宽度符 | 描述 |
数字 | 该数字为大于0的十进制整数,表示最小字段宽度。 |
* | 该字符表示最小字段宽度,该字符并未直接指定字段宽度,需要在转换参数前有一个额外整值参数来指定字段宽度,例如:snprintf(s, sizeof(s)/sizeof(s[0]), "%*d", width, value);,其中参数width指定字段宽度。如果width是负整数,转换结果是左对齐的。 |
如果字段宽度为负值,就相当于使用其绝对值作为字段宽度,-字符作为标记符。
如果转换值含有的字符数小于字段宽度,默认情况下在转换值左边填充空格;如果转换值含有的字符数大于等于字段宽度,转换值正常输出。
3、精度符及其意义
精度符 | 描述 |
.数字 | 该数字为十进制整数。 |
.* | 该字符未直接指定精度,需要在转换参数前有一个额外整值参数指定精度,例如:snprintf(s, sizeof(s)/sizeof(s[0]), "%.*f", precision, value);,其中参数precision指定精度。 |
对于d、i、o、u、x、X转换,精度符表示出现的最小位数。对于a、A、e、E、f、F转换,精度符表示小数点后出现的位数。对于g、G转换,精度符表示最大有效位数。对于s转换,精度符表示写入的最大字节数。如果只指定.字符,精度值为0。
如果精度符与除上面指定的转换说明符一起使用,其行为是未定义的。
4、长度修饰符及其意义
长度修饰符 | 描述 |
hh | 对于d、i、o、u、x、X转换说明符,该字符用于signed char或者unsigned char类型参数(参数会被整数提升,但在输出前参数值应转换为signed char或者unsigned char类型。)。对于n转换说明符,该字符用于signed char类型指针。 |
h | 对于d、i、o、u、x、X转换说明符,该字符用于short int或者unsigned short int类型参数(参数会被整数提升,但在输出前参数值应转换为short int或者unsigned short int类型。)。对于n转换说明符,该字符用于short int类型指针。 |
l | 对于d、i、o、u、x、X转换说明符,该字符用于long int或者unsigned long int类型参数。对于n转换说明符,该字符用于long int类型指针。对于c转换说明符,该字符用于wint_t类型参数。对于s转换说明符,该字符用于wchar_t类型指针。对于a、A、e、E、f、F、g、G转换说明符,该字符不起作用。 |
ll | 对于d、i、o、u、x、X转换说明符,该字符用于long long int或者unsigned long long int类型参数。对于n转换说明符,该字符用于long long int类型指针。 |
j | 对于d、i、o、u、x、X转换说明符,该字符用于intmax_t或者uintmax_t类型参数。对于n转换说明符,该字符用于intmax_t类型指针。 |
z | 对于d、i、o、u、x、X转换说明符,该字符用于size_t或者对应的有符号整数类型参数。对于n转换说明符,该字符用于对应size_t的有符号整数类型指针。 |
t | 对于d、i、o、u、x、X转换说明符,该字符用于ptrdiff_t或者对应的无符号整数类型参数。对于n转换说明符,该字符用于ptrdiff_t类型指针。 |
L | 对于a、A、e、E、f、F、g、G转换说明符,该字符用于long double类型参数。 |
如果长度修饰符与除上面指定的转换说明符一起使用,其行为是未定义的。
5、转换说明符及其意义
转换说明符 | 描述 |
d,i | int类型参数转换为有符号十进制整数。精度指定转换结果的最小位数。如果转换结果的位数小于精度值,将添加前导0。默认精度为1。精度为0的0值转换结果没有字符。(注:转换说明符d、i对于格式化输出函数(例如:vsnprintf函数)是没有区别的;但对于格式化输入函数(例如:sscanf函数)两者是有区别的。) |
o,u,x,X | unsigned int类型参数转换为无符号的八进制整数(o)、十进制整数(u)或者十六进制整数(x或者X)。小写字母abcdef用作x转换;大写字母ABCDEF用作X转换。精度指定转换结果的最小位数。如果转换结果的位数小于精度值,将添加前导0。默认精度为1。精度为0的0值转换结果没有字符。 |
f,F | double类型参数转换为[-]ddd.ddd形式的十进制浮点数,其中小数点后位数等于精度值。如果没有指定精度,默认精度为6。如果精度为0,并且没有使用#标记符,将不会出现小数点。如果转换结果中出现小数点,小数点前至少有一位数。转换结果会被舍入到合适的位数。 如果double类型参数表示无穷大,是转换成[-]inf形式还是转换成[-]infinity形式将由实现定义。如果double类型参数表示非数值,是转换成[-]nan形式还是转换成[-]nan(n-char-sequence)形式,以及n-char-sequence的含义将由实现定义。f转换说明符对应inf、infinity或者nan;F转换说明符对应INF、INFINITY或者NAN。(注:当用于无穷大和非数值时,-、+和空格标记符具有其通常的含义;但#和0标记符没有影响。) |
e,E | double类型参数转换为科学计数法形式([-]d.ddde±dd),其中小数点前有一位数,如果参数是非0值,该数也是非0值;小数点后位数等于精度值。如果没有指定精度,默认精度为6。如果精度为0,并且没有使用#标记符,将不会出现小数点。转换结果会被舍入到合适的位数。e转换说明符对应指数为e;E转换说明符对应指数为E。指数位数至少为2位;并且仅包含表示指数所需的更多位数。如果参数值为0,指数为0。 如果double类型参数表示无穷大,是转换成[-]inf形式还是转换成[-]infinity形式将由实现定义。如果double类型参数表示非数值,是转换成[-]nan形式还是转换成[-]nan(n-char-sequence)形式,以及n-char-sequence的含义将由实现定义。e转换说明符对应inf、infinity或者nan;E转换说明符对应INF、INFINITY或者NAN。(注:当用于无穷大和非数值时,-、+和空格标记符具有其通常的含义;但#和0标记符没有影响。) |
g,G | double类型参数表示的浮点数是按e转换说明符还是按f转换说明符进行转换(对于G转换说明符,对应的是E转换说明符和F转换说明符。)取决于转换值和精度。声明一个变量P,如果精度值为非0值,P等于精度值;如果省略精度,P等于6;如果精度值为0,P等于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转换说明符对应inf、infinity或者nan;G转换说明符对应INF、INFINITY或者NAN。(注:当用于无穷大和非数值时,-、+和空格标记符具有其通常的含义;但#和0标记符没有影响。) |
a,A | double类型参数表示的浮点数将转换成[-]0xh.hhhhp±d形式,其中小数点前有1位十六进制数(如果参数是规格化浮点数(normalized floating-point number),该十六进制数为非0值;否则其值是不确定的。);小数点后十六进制数的位数与精度值相同。如果没有指定精度并且FLT_RADIX是2的幂,那么精度足以精确表示转换值。如果没有指定精度并且FLT_RADIX不是2的幂,那么精度足以区分double类型的值,但尾随0可能会被省略。如果精度为0,并且没有使用#标记符,将不会出现小数点。字母abcdef用于a转换;字母ABCDEF用于A转换。a转换的转换结果使用x和p;A转换的转换结果使用X和P。指数位数至少为1位;并且仅包含表示2的十进制指数所需的更多位数。如果值为0,指数为0。 如果double类型参数表示无穷大,是转换成[-]inf形式还是转换成[-]infinity形式将由实现定义。如果double类型参数表示非数值,是转换成[-]nan形式还是转换成[-]nan(n-char-sequence)形式,以及n-char-sequence的含义将由实现定义。a转换说明符对应inf、infinity或者nan;A转换说明符对应INF、INFINITY或者NAN。(注:当用于无穷大和非数值时,-、+和空格标记符具有其通常的含义;但#和0标记符没有影响。) |
c |
如果不存在l长度修饰符,int类型参数将转换为unsigned char类型,并将结果字符写入数组。 如果存在l长度修饰符,wint_t类型参数的转换就像一个未指定精度的ls转换,并且参数指向wchar_t类型的由两个元素构成的数组的初始元素,其中第一个元素为进行lc转换的wint_t类型参数,第二个元素为空宽字符。 |
s |
如果不存在l长度修饰符,参数应为指向字符数组初始元素的指针。数组中的字符将写入参数s指向的数组,直至但不包括终止空字符。如果指定了精度,写入的字节数不超过精度值。如果没有指定精度或者精度值大于数组长度,数组应包含空字符。 如果存在l长度修饰符,参数应为指向wchar_t类型数组初始元素的指针。数组中的宽字符将转换成多字节字符(每个宽字符就像调用wcrtomb函数一样转换成多字节字符,第一个宽字符转换前,将mbstate_t对象描述的转换状态初始化为0。),直至并包括终止空宽字符。生成的多字节字符将被写入参数s指向的数组,直至但不包括终止空字符(字节)。如果没有指定精度,数组应包含空宽字符。如果指定了精度,写入参数s指向数组的字节数(包括移位序列,如果存在。)不超过精度值;如果为等于由精度值指定的多字节字符序列长度,数组应包含一个空宽字符,函数需要访问数组后的第一个宽字符。任何情况下都不能向参数s指向的数组写入部分多字节字符。 |
p | 参数应为void类型指针。指针值转换为实现定义的打印字符序列。 |
n | 参数应为一个指向有符号整数的指针,到目前为止通过调用vsprintf_s函数写入到参数s指向数组的字符数将写入该整数。对于该转换说明符,没有参数被转换,但消耗一个参数。如果转换说明包含标记符、字段宽度符或者精度符,该转换说明符的行为是未定义的。 |
% | 向数组写入一个%字符。没有参数被转换。完整的转换说明为%%。 |
长度修饰符、转换说明符和对应的参数类型如下表所示:
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_RADIX为2的幂,转换值准确地舍入为具有指定精度的十六进制浮点数。
va_list类型对象。
返回值:
如果不存在运行约束冲突,函数返回写入数组的字符数(不包括终止空字符。);如果发生编码错误,函数返回一个负值;如果发生其它运行约束冲突,函数返回0。
范例:
|
|
输出:
No.1 Archives
Name: Zhangshan
No.2 Archives
Name: Lisi
Gender: M
No.3 Archives
Name: Wangwu
Gender: M
Age: 25
注:使用Visual Studio编译。
相关内容:
vprintf_s | 将输出写入标准输出流的安全函数。 |
vsnprintf_s | 将限定大小的输出写入数组的安全函数。 |
vfprintf_s | 将输出写入流的安全函数。 |