当前位置: C语言 -- 附录 -- snwprintf_s

snwprintf_s函数


概要:
#define __STDC_WANT_LIB_EXT1__ 1
#include <wchar.h>
int snwprintf_s(wchar_t * restrict s,
     rsize_t n,
     const wchar_t * restrict format, ...);

描述:

该函数将输出写入参数s指向的数组,最多可以写入(n-1)个宽字符,并在写入宽字符末尾添加空宽字符,但空宽字符不作为函数返回值的一部分;参数format指向的宽字符串指定后续参数如何转换为输出。

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

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

该函数等价于swprintf函数,区别在于snwprintf_s函数存在运行约束。

swprintf_s函数不同,snwprintf_s函数会截断结果以适应参数s指向的数组。


运行约束:

参数sformat不能是空指针。参数n既不能等于0,也不能大于RSIZE_MAX/sizeof(wchar_t)。转换说明%n不能出现在参数format指向的字符串中;但如果%n不被解释为转换说明,则不会引起运行约束冲突,例如:L"%%n"。与转换说明%s对应的参数不能为空指针。不能发生编码错误。

如果存在运行约束冲突,并且参数s不是空指针,参数n大于0且不大于RSIZE_MAX/sizeof(wchar_t),函数snwprintf_ss[0]设置为空宽字符。


参数:
wchar_t * restrict s

指向wchar_t类型对象指针,结果字符串将存储在该对象中。该对象必须足够大,能够容纳结果字符串。


rsize_t n

指定写入宽字符的最大数量,最大数量为(n-1),不包括末尾空宽字符。


const wchar_t * restrict format

wchar_t类型指针,指向格式字符串。格式字符串应为宽字符序列;构成格式序列的指令分为以下两种情况:

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

普通宽字符不作任何改变写入数组。


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

每个转换说明都会获取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的十进制整数,表示最小字段宽度。

*

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

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

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


3、精度符及其意义

精度符 描述
.数字

该数字为十进制整数。

.*

该字符未直接指定精度,需要在转换参数前有一个额外整值参数来指定精度,例如:snwprintf_s(s, sizeof(s)/sizeof(s[0]), L"%.*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对于格式化输出函数(例如:fwprintf函数)是没有区别的;对于格式化输入函数(例如:fwscanf函数)两者是有区别的。)

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-wchar-sequence)形式,以及n-wchar-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-wchar-sequence)形式,以及n-wchar-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-wchar-sequence)形式,以及n-wchar-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-wchar-sequence)形式,以及n-wchar-sequence的含义将由实现定义。a转换说明符对应infinfinity或者nanA转换说明符对应INFINFINITY或者NAN。(:当用于无穷大和非数值时,-+和空格标记符具有其通常的含义;但#0标记符没有影响。)

c

如果不存在l长度修饰符,int类型参数就像调用btowc函数一样转换为宽字符,并将结果宽字符写入数组。

如果存在l长度修饰符,wint_t类型参数将转换为wchar_t类型,并写入数组。

s

如果不存在l长度修饰符,参数应为指向字符数组初始元素的指针,该数组包含处于初始移位状态的多字节字符序列。数组中的字符就像反复调用mbrtowc函数一样转换为宽字符(第一个多字节字符转换前,描述转换状态的mbstate_t对象应初始化为0。),并将结果宽字符写入参数s指向的数组直至终止空宽字符(但不包括终止空宽字符)。如果指定精度,写入的宽字符数不超过精度值。如果没有指定精度或者精度值大于转换后的数组长度,转换后的数组应包含一个空宽字符。

如果存在l长度修饰符,参数应为指向wchar_t类型数组初始元素的指针。数组中的宽字符将被写入参数s指向的数组,直至终止空宽字符(但不包括终止空宽字符)。如果指定精度,写入的宽字符数不超过精度值。如果没有指定精度或者精度值大于数组长度,数组应包含一个空宽字符。

p

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

n

参数应为一个指向有符号整数的指针,到目前为止通过调用snwprintf_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_RADIX2的幂,转换值准确地舍入为具有指定精度的十六进制浮点数。


...

参数列表。参数列表应与转换说明相对应。


返回值:

如果n足够大,函数返回写入数组的宽字符数(不包括终止空宽字符。);如果发生运行约束冲突,函数返回一个负值。因此当且仅当返回值为非负值且小于n时,输出字符串才会完全被写入数组。


范例:
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
/*安全函数snwprintf_s范例*/

#define __STDC_WANT_LIB_EXT1__ 1
#include <locale.h>
#include <wchar.h>

#define LENGTH 100

int main(void)
{
    setlocale(LC_ALL, "");
    wchar_t wArr[LENGTH];
    const wchar_t wStr[] = L"三军可夺帅也,匹夫不可夺志也。";
    
    snwprintf_s(wArr, LENGTH, L"%ls", wStr);
    wprintf_s(L"%ls\n", wArr);

    return 0;
}


可能输出:

三军可夺帅也,匹夫不可夺志也。

注:测试时Visual Studio软件还未支持snwprintf_s函数。以上结果仅供参考。


相关内容:
wprintf_s 将输出写入标准输出流的安全函数。
fwprintf_s 将输出写入流的安全函数。
swprintf_s 将输出写入数组的安全函数。