细说C语言将格式化输出到字符串的函数sprintf、_sprintf_l、swprintf、_swprintf_l、__swprintf_l
目录
1、 将格式的数据写入字符串函数基本型
(1)语法
(2)参数
(3)示例1
(4)示例2
2、 将格式的数据写入字符串函数,并启用在格式字符串中使用参数的顺序的规范
(1)语法
(2)参数
(3)示例
(4)运行结果
3、 将格式的数据写入字符串函数的安全版本
(1)语法
(2)参数
(3)示例1
(4)示例2
C语言将格式化输出到字符串的函数的外观表达是以sprintf()为根的。将格式化输出到字符串的函数有:
1、 将格式的数据写入字符串函数基本型
sprintf、_sprintf_l、swprintf、_swprintf_l、__swprintf_l
其中的一部分函数在VS2022 17.13.6以上版本上都被弃用了,如果执意要用,需增加以下预编译,否则,会出现警告C4996,并且没有编译结果。
#define _CRT_SECURE_NO_WARNINGS
错误 C4996 'sprintf': This function or variable may be unsafe. Consider using sprintf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
(1)语法
/**
sprintf 函数存储 buffer 中的一系列字符和值并设置格式。 每个 argument (如果有)根据 format中相应的格式规范进行转换和输出。 该格式包括普通字符,其形式和函数与 format 的 printf 参数相同。 null 字符追加在写入的最后一个字符后。 如果在重叠的字符串之间发生复制,则此行为不确定。
swprintf 是 sprintf的宽字符版本; swprintf 的指针参数是宽字符串。 swprintf 中的编码错误检测可能与 sprintf 中的不同。 swprintf 和 fwprintf 行为完全相同,只不过 swprintf 将输出写入到一个字符串,而不是 FILE 类型的目标,并且 swprintf 需要 count 参数来指定要写入的最大字符数。 这些带有 _l 后缀的函数的版本相同,只不过它们使用传递的区域设置参数而不是当前线程区域设置。
在标准化 swprintf 签名之前,旧版 Microsoft C 运行时库中提供的版本不采用字符计数参数。 旧版本仍然可以在 Microsoft C 运行时库中使用,但其已被弃用并重命名为 _swprintf()。 对于针对旧版签名编写的代码,请定义 _CRT_NON_CONFORMING_SWPRINTFS,以将对 swprintf 的调用映射到 _swprintf。 在未来版本中,可能会删除旧行为,因此应将代码更改为使用新的符合标准行为。
在 C++ 中,这些函数具有模板重载,以调用这些函数的更新、更安全副本。
*/int sprintf(char *buffer,const char *format [,argument] ...
);int _sprintf_l(char *buffer,const char *format,_locale_t locale [,argument] ...
);int swprintf(wchar_t *buffer,size_t count,const wchar_t *format [,argument]...
);int _swprintf(wchar_t *buffer,const wchar_t *format [,argument]...
);int _swprintf_l(wchar_t *buffer,size_t count,const wchar_t *format,_locale_t locale [,argument] ...
);int __swprintf_l(wchar_t *buffer,const wchar_t *format,_locale_t locale [,argument] ...
);template <size_t size>
int sprintf(char (&buffer)[size],const char *format [,argument] ...
); // C++ onlytemplate <size_t size>
int _sprintf_l(char (&buffer)[size],const char *format,_locale_t locale [,argument] ...
); // C++ only
(2)参数
- buffer:输出的存储位置
- count:要存储在 Unicode 版的此函数中的最大字符数。
- format:格式控件字符串
- argument:可选自变量
- locale:要使用的区域设置。
- 返回值:写入的字符数或 -1(如果发生错误)。 如果 buffer 或 format 是空指针,则会调用无效的参数处理程序,如参数验证中所述。 如果允许继续执行,则这些函数返回 -1 并将 errno 设置为 EINVAL。sprintf 返回存储在 buffer中的字节数,不包括终止 null 字符。 swprintf 返回存储在 buffer 中的宽字符数,不包括中止 null 宽字符。
(3)示例1
// test_sprintf.c
// compile with: /W3
// This program uses sprintf to format various
// data and place them in the string named buffer.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>int main(void)
{char buffer[200], s[] = "computer", c = 'l';int i = 35, j;float fp = 1.7320534f;// Format and print various data:j = sprintf(buffer, " String: %s\n", s); // C4996j += sprintf(buffer + j, " Character: %c\n", c); // C4996j += sprintf(buffer + j, " Integer: %d\n", i); // C4996j += sprintf(buffer + j, " Real: %f\n", fp); // C4996// Note: sprintf is deprecated; consider using sprintf_s insteadprintf("Output:\n%s\ncharacter count = %d\n", buffer, j);
}
Output:String: computerCharacter: lInteger: 35Real: 1.732053character count = 79C:\Users\YCZN_MT\Test_sprintf\x64\Debug\Test_sprintf.exe (进程 24964)已退出,代码为 0 (0x0)。
按任意键关闭此窗口. . .
(4)示例2
// test_swprintf.c
// wide character example
// also demonstrates swprintf returning error code
#include <stdio.h>int main(void)
{wchar_t buf[100];int len = swprintf(buf, 100, L"%s", L"Hello world");printf("wrote %d characters\n", len);len = swprintf(buf, 100, L"%s", L"Hello\xffff world");printf("wrote %d characters\n", len);len = swprintf(buf, 100, L"%s", L"Hello\xFFFF world");printf("wrote %d characters\n", len);len = swprintf(buf, 100, L"%s", L"Hello\n world");printf("wrote %d characters\n", len);len = swprintf(buf, 100, L"%s", L"Hello\0 world");printf("wrote %d characters\n", len);
}
wrote 11 characters
wrote 12 characters
wrote 12 characters
wrote 12 characters
wrote 5 charactersC:\Users\YCZN_MT\Test_swprintf\x64\Debug\Test_swprintf.exe (进程 23544)已退出,代码为 0 (0x0)。
按任意键关闭此窗口. . .
2、 将格式的数据写入字符串函数,并启用在格式字符串中使用参数的顺序的规范
利用指定参数在格式字符串中使用的顺序的能力将带格式的数据写入字符串。
_sprintf_p, _sprintf_p_l, _swprintf_p, _swprintf_p_l
(1)语法
/**
_sprintf_p 函数存储 buffer 中的一系列字符和值并设置格式。 argument_list 中的每个参数(如果有)根据 format 中相应的格式规范进行转换和输出。 format 参数使用 printf 和 wprintf 函数的格式规范语法。 null 字符追加在写入的最后一个字符后。 如果在重叠的字符串之间发生复制,则此行为不确定。 _sprintf_p 和 sprintf_s 之间的差异在于 _sprintf_p 支持位置参数,这允许指定格式字符串中使用参数的顺序。
_swprintf_p 是 _sprintf_p的宽字符版本; _swprintf_p 的指针参数是宽字符串。 _swprintf_p 中的编码错误检测可能与 _sprintf_p 中的检测不同。 _swprintf_p 和 fwprintf_p 行为完全相同,只不过 _swprintf_p 将输出写入到一个字符串,而不是类型 FILE 的目标,并且 _swprintf_p 需要 count 参数来指定要写入的最大字符数。 这些带有 _l 后缀的函数的版本相同,只不过它们使用传递的区域设置参数而不是当前线程区域设置。
_sprintf_p 返回存储在 buffer中的字节数,不包括终止 null 字符。 _swprintf_p 返回存储在 buffer 中的宽字符数,不包括中止 null 宽字符。 如果 buffer 或 format 为 null 指针,或如果格式字符串包含无效格式字符,则将调用无效参数处理程序,如参数验证中所述。 如果允许继续执行,则这些函数返回 -1 并将 errno 设置为 EINVAL。
*/int _sprintf_p(char *buffer,size_t sizeOfBuffer,const char *format [,argument_list]
);
int _sprintf_p_l(char *buffer,size_t sizeOfBuffer,const char *format,_locale_t locale [,argument_list]
);
int _swprintf_p(wchar_t *buffer,size_t sizeOfBuffer,const wchar_t *format [,argument_list]
);
int _swprintf_p_l(wchar_t *buffer,size_t sizeOfBuffer,const wchar_t *format,_locale_t locale [,argument_list]
);
(2)参数
- buffer:输出的存储位置
- sizeOfBuffer:可存储的最多字符数。
- format:窗体控件字符串。
- argument_list:格式字符串的可选参数。
- locale:要使用的区域设置。
- 返回值:写入的字符数或 -1(如果发生错误)。
(3)示例
// test_sprintf_p.c
// This program uses _sprintf_p to format various
// data and place them in the string named buffer.
//#include <stdio.h>int main( void )
{char buffer[200],s[] = "computer", c = 'l';int i = 35,j;float fp = 1.7320534f;// Format and print various data:j = _sprintf_p( buffer, 200," String: %s\n", s );j += _sprintf_p( buffer + j, 200 - j," Character: %c\n", c ); //C6386j += _sprintf_p( buffer + j, 200 - j," Integer: %d\n", i );j += _sprintf_p( buffer + j, 200 - j," Real: %f\n", fp );printf( "Output:\n%s\ncharacter count = %d\n",buffer, j );
}
在VS2022提示C6386警告,并且显示3条消息:在分配到更广的类型之前,子表达式可能溢出。修改为如下代码,警告和提示均消除:
// test_sprintf_p.c
// This program uses _sprintf_p to format various
// data and place them in the string named buffer.#include <stdio.h>
#include <string.h> //strlen()
#include <stdlib.h > //_gcvt_s()、 _itoa_sint main(void)
{char buffer[200],s[] = "computer", c = 'l';int i = 35, j;float fp = 1.7320534f;char str[50] = {0};// Format and print various data:j = _sprintf_p(buffer, 200," String: %s\n", s);_itoa_s(c, str,50, 10); //char to stringj += _sprintf_p(buffer + j, j+strlen(str)," Character: %c\n", c);_itoa_s(i, str,50, 10); //int to stringj += _sprintf_p(buffer + j, j+strlen(str), " Integer: %d\n", i);_gcvt_s(str,50,fp, 7); //float to stringj += _sprintf_p(buffer + j, j+strlen(str), " Real: %f\n", fp);printf("Output:\n%s\ncharacter count = %d\n",buffer, j);
}
(4)运行结果
Output:String: computerCharacter: lInteger: 35Real: 1.732053character count = 79C:\Users\YCZN_MT\Test_sprintf_p\x64\Debug\Test_sprintf_p.exe (进程 22172)已退出,代码为 0 (0x0)。
按任意键关闭此窗口. . .
3、 将格式的数据写入字符串函数的安全版本
sprintf_s、_sprintf_s_l、swprintf_s、_swprintf_s_l
(1)语法
/**
sprintf_s 函数存储 buffer 中的一系列字符和值并设置格式。 每个 argument (如果有)根据 format中相应的格式规范进行转换和输出。 该格式包括普通字符,其形式和函数与 format 的 printf 参数相同。 null 字符追加在写入的最后一个字符后。 如果在重叠的字符串之间发生复制,则此行为不确定。sprintf_s 和 sprintf 之间的一个主要区别是, sprintf_s 检查格式字符串中的有效格式设置字符,而 sprintf 仅检查格式字符串或缓冲区是否为 NULL 指针。 如果任一检查失败,将调用无效参数处理程序,如 Parameter Validation中所述。 如果允许执行继续,则该函数将返回 -1 并将 errno 设置为 EINVAL。sprintf_s 和 sprintf 之间的另一主要区别是, sprintf_s 使用长度参数来指定字符中输出缓冲区的大小。 如果缓冲区对于格式化文本(包括终止 null)来说太小,则将通过在 buffer[0]处放置 null 字符而将缓冲区设置为空字符串,并调用无效的参数处理程序。 与 _snprintf不同, sprintf_s 可保证缓冲区以 null 终止(除非缓冲区大小为零)。swprintf_s 是 sprintf_s的宽字符版本; swprintf_s 的指针参数是宽字符串。 swprintf_s 中的编码错误检测可能与 sprintf_s 中的检测不同。 这些带有 _l 后缀的函数的版本相同,只不过它们使用传递的区域设置参数而不是当前线程区域设置。
*/int sprintf_s(char *buffer,size_t sizeOfBuffer,const char *format,...
);
int _sprintf_s_l(char *buffer,size_t sizeOfBuffer,const char *format,_locale_t locale,...
);
int swprintf_s(wchar_t *buffer,size_t sizeOfBuffer,const wchar_t *format,...
);
int _swprintf_s_l(wchar_t *buffer,size_t sizeOfBuffer,const wchar_t *format,_locale_t locale,...
);
template <size_t size>
int sprintf_s(char (&buffer)[size],const char *format,...
); // C++ only
template <size_t size>
int swprintf_s(wchar_t (&buffer)[size],const wchar_t *format,...
); // C++ only
(2)参数
- buffer:输出的存储位置
- sizeOfBuffer:可存储的最多字符数。
- format:格式控件字符串
- locale:要使用的区域设置。
- 返回值:写入的字符数或 -1(如果发生错误)。 如果 buffer 或 format 是 null 指针,sprintf_s 和 swprintf_s 将返回 -1 并将 errno 设置为 EINVAL。sprintf_s 返回存储在 buffer中的字节数,不包括终止 null 字符。 swprintf_s 返回存储在 buffer 中的宽字符数,不包括中止 null 宽字符。
(3)示例1
// test_sprintf_s.c
// This program uses sprintf_s to format various
// data and place them in the string named buffer.
//#include <stdio.h>int main(void)
{char buffer[200], s[] = "computer", c = 'l';int i = 35, j;float fp = 1.7320534f;// Format and print various data:j = sprintf_s(buffer, 200, " String: %s\n", s);j += sprintf_s(buffer + j, 200 - j, " Character: %c\n", c);j += sprintf_s(buffer + j, 200 - j, " Integer: %d\n", i);j += sprintf_s(buffer + j, 200 - j, " Real: %f\n", fp);printf_s("Output:\n%s\ncharacter count = %d\n", buffer, j);
}
有提示,在分配到更广的类型之前,子表达式可能溢出,修改为如下代码,提示消除:
Output:String: computerCharacter: lInteger: 35Real: 1.732053character count = 79C:\Users\YCZN_MT\Test_sprintf_s\x64\Debug\Test_sprintf_s.exe (进程 3484)已退出,代码为 0 (0x0)。
按任意键关闭此窗口. . .
(4)示例2
#include <stdio.h>int main() {char buffer[200];int hour = 10, minute = 20, second = 30;sprintf_s(buffer, sizeof(buffer), "%02d:%02d:%02d", hour, minute, second);printf("Formatted Time: %s\n", buffer);return 0;
}
Formatted Time: 10:20:30C:\Users\YCZN_MT\Test_sprintfs_2\x64\Debug\Test_sprintfs_2.exe (进程 18496)已退出,代码为 0 (0x0)。
按任意键关闭此窗口. . .