std::vscanf, std::vfscanf, std::vsscanf
在标头 <cstdio> 定义 | ||
int vscanf(constchar* format, std::va_list vlist ); | (1) | (C++11 起) |
int vfscanf(std::FILE* stream, constchar* format, std::va_list vlist ); | (2) | (C++11 起) |
int vsscanf(constchar* buffer, constchar* format, std::va_list vlist ); | (3) | (C++11 起) |
从各种源读取数据,按照 format 转换并存储结果到 vlist 所定义的位置。
目录 |
[编辑]参数
stream | - | 要读取的输入文件流 |
buffer | - | 指向要读取的空终止字符串的指针 |
format | - | 指向空终止字符串的指针,指定如何读取输入 |
vlist | - | 含有接收实参的可变参数列表 |
格式字符串由下列内容组成
- 非空白多字节字符,除了
%
:每个格式字符串中的这种字符处理一个来自输入流的完全相同的字符,或在它与流的下个字符比较不相等时导致函数失败。 - 空白字符:任何格式字符串中的单个空白字符处理所有来自输入的可用连续空白字符(如同通过于循环中调用 std::isspace 确定)。注意,格式字符串中 "\n"、" "、"\t\t" 或其他空白无区别。
- 转换指示:每个转换指示拥有下列格式:
- 引入用 % 字符
- (可选) 赋值抑制字符 *。如果存在此选项,那么此函数不将结果赋值给任何接收用实参。
- (可选) 指定最大字段宽度 的整数数字(大于零),即函数进行在当前转换指示所指定的转换时,允许处理的最大字符数。注意如果没有提供宽度,那么 %s 和 %[ 可能导致缓冲区溢出。
- (可选) 指定接收实参大小的长度修饰符,即实际目标类型。这影响转换准确性和溢出规则。默认目标类型对每个转换类型有所不同(见下表)。
- 转换格式指示符。
下列格式指示符可用:
转换指示符 | 解释 | 期望的实参类型 | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
长度修饰符→ | hh | h | 无 | l | ll | j | z | t | L | |
仅从 C++11 起可用→ | 是 | 是 | 是 | 是 | 是 | |||||
% | 匹配字面 % 。 | 不适用 | 不适用 | 不适用 | 不适用 | 不适用 | 不适用 | 不适用 | 不适用 | 不适用 |
c | 匹配一个字符或字符的序列。
| 不适用 | 不适用 | char* | wchar_t* | 不适用 | 不适用 | 不适用 | 不适用 | 不适用 |
s | 匹配非空白字符的序列(一个字符串)。
| |||||||||
[ 集合 ] | 匹配集合 中的字符的一个非空字符序列。
| |||||||||
d | 匹配一个十进制整数。
| signedchar* 或 unsignedchar* | signedshort* 或 unsignedshort* | signedint* 或 unsignedint* | signedlong* 或 unsignedlong* | signedlonglong* 或 unsignedlonglong* | 不适用 | |||
i | 匹配一个整数。
| |||||||||
u | 匹配一个无符号十进制整数。
| |||||||||
o | 匹配一个无符号八进制数。
| |||||||||
x X | 匹配一个无符号十六进制整数。
| |||||||||
n | 返回迄今读取的字符数。
| |||||||||
a (C++11)A (C++11)e E f F (C++11)g G | 匹配一个浮点数。
| 不适用 | 不适用 | float* | double* | 不适用 | 不适用 | 不适用 | 不适用 | longdouble* |
p | 匹配定义了一个指针的由实现定义的字符序列。
| 不适用 | 不适用 | void** | 不适用 | 不适用 | 不适用 | 不适用 | 不适用 | 不适用 |
注解 | ||||||||||
对于每个 n 以外的转换指示符,不超过任何指定字段宽度,且要么恰好是转换指示符所期待,要么是其所期待的前缀的最长输入字符序列,即是从流中消耗的内容。此消耗序列后的首个字符如果存在,那么保持未读取。如果被消耗序列长度为零,或被消耗序列不能转换成上面所指定的项目,那么发生匹配失败,除非遇到文件尾、编码错误,或阻止从流输入的读取错误,此情况下此为输入失败。 所有异于 [、c 和 n 的转换指示符,在尝试分析输入前消耗并舍弃所有前导空白字符(如同以调用 std::isspace 来确定)。这些被消耗的字符不计入指定的最大字段宽度。 转换指示符 lc、ls 和 l[ 进行多字节到宽字符转换,如同如同在转换首字符前,通过用初始化为零的 std::mbstate_t 对象调用 std::mbrtowc。 转换指示符 s 与 [ 始终在匹配字符之后存储一个空字符。目标数组的大小必须至少比指定字段宽度大一。未指定目标数组大小时,对 %s 或 %[ 的使用,与 std::gets 同样不安全。 定宽整数类型(std::int8_t 等)的正确的转换指示在标头 <cinttypes> 定义(虽然 SCNdMAX、SCNuMAX 等就是 %jd、%ju 等的别名)。 在每个转换指示符后有一个序列点;这允许存储多个字段到同一“池”变量中。 在分析以无数字指数为结尾的不完整浮点数,如以转换指示符 %f 分析 "100er" 时,消耗序列 "100e" (可能为合法浮点数的最长前缀),并导致匹配错误(被消耗序列不能转换成浮点数),而留下 "r"。某些既存实现不遵守此规则并回滚,通过消耗 "100" 而留下 "er",例如 glibc 漏洞 1765。 如果转换指示非法,那么行为未定义。 |
[编辑]返回值
成功读取的实参个数,或若出现失败则为 EOF。
[编辑]注解
所有这些函数调用 va_arg 至少一次,返回后 arg
的值不确定。这些函数不调用 va_end,而这必须由调用方进行。
[编辑]示例
#include <cstdarg>#include <cstdio>#include <iostream>#include <stdexcept> void checked_sscanf(int count, constchar* buf, constchar*fmt, ...){ std::va_list ap;va_start(ap, fmt);if(std::vsscanf(buf, fmt, ap)!= count)throwstd::runtime_error("parsing error");va_end(ap);} int main(){try{int n, m;std::cout<<"Parsing '1 2'... "; checked_sscanf(2, "1 2", "%d %d", &n, &m);std::cout<<"success\n";std::cout<<"Parsing '1 a'... "; checked_sscanf(2, "1 a", "%d %d", &n, &m);std::cout<<"success\n";}catch(conststd::exception& e){std::cout<< e.what()<<'\n';}}
输出:
Parsing '1 2'... success Parsing '1 a'... parsing error
[编辑]参阅
从 stdin、文件流或缓冲区读取有格式输入 (函数) | |
使用可变实参列表 打印有格式输出到 stdout、文件流或缓冲区 (函数) | |
vscanf, vfscanf, vsscanf 的 C 文档 |