std::vscanf, std::vfscanf, std::vsscanf
定义在头文件 <cstdio> 中 |
||
int vscanf( const char* format, std::va_list vlist ); |
(1) | (自 C++11 起) |
int vfscanf( std::FILE* stream, const char* format, std::va_list vlist ); |
(2) | (自 C++11 起) |
int vsscanf( const char* buffer, const char* format, std::va_list vlist ); |
(3) | (自 C++11 起) |
从各种来源读取数据,根据 format 解释数据,并将结果存储到由 vlist 定义的位置。
内容 |
[编辑] 参数
stream | - | 要从中读取的输入文件流 |
buffer | - | 指向要从中读取的以 null 结尾的字符字符串的指针 |
format | - | 指向指定如何读取输入的以 null 结尾的字符字符串的指针 |
vlist | - | 包含接收参数的可变参数列表。 |
format 字符串包含
- 非空白多字节字符,除了 %:格式字符串中的每个这样的字符都会从输入流中消耗一个完全相同的字符,或者如果流上的下一个字符不相等,则导致函数失败。
- 空白字符:格式字符串中的任何单个空白字符都会消耗输入流中所有可用的连续空白字符(就像调用 isspace 在循环中一样)。请注意,"\n"、" "、"\t\t" 或格式字符串中的其他空白之间没有区别。
- 转换说明。每个转换说明都具有以下格式
- 介绍性 % 字符。
- (可选) 赋值抑制字符 *。如果存在此选项,则函数不会将转换结果分配给任何接收参数。
- (可选) 整数(大于零),指定最大字段宽度,即函数在执行当前转换说明指定的转换时允许消耗的最大字符数。请注意,%s 和 %[ 如果未提供宽度,可能会导致缓冲区溢出。
- (可选) 长度修饰符,指定接收参数的大小,即实际目标类型。这会影响转换精度和溢出规则。默认目标类型对于每种转换类型都不同(请参见下表)。
- 转换格式说明符。
以下格式说明符可用
转换 说明符 |
说明 | 参数类型 | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
长度修饰符 →
|
hh
(C++11) |
h
|
(无) | l
|
ll
(C++11) |
j
(C++11) |
z
(C++11) |
t
(C++11) |
L
| |
%
|
匹配文字 % 。 |
N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A |
c
|
如果使用宽度说明符,则精确匹配宽度个字符(参数必须是指向具有足够空间的数组的指针)。与 %s 和 %[ 不同,它不会在数组中追加 null 字符。 |
N/A | N/A | char* |
wchar_t* |
N/A | N/A | N/A | N/A | N/A |
s
|
如果使用宽度说明符,则最多匹配宽度或直到第一个空白字符,以先出现的为准。始终存储一个 null 字符,除了匹配的字符之外(因此参数数组必须至少有宽度+1个字符的空间) | |||||||||
[ set] |
如果集合的第一个字符是 | |||||||||
d
|
数字的格式与strtol 预期的相同, |
signed char* 或 unsigned char* |
signed short* 或 unsigned short* |
signed int* 或 unsigned int* |
signed long* 或 unsigned long* |
signed long long* 或 unsigned long long* |
intmax_t* 或 uintmax_t* |
size_t* |
ptrdiff_t* |
N/A |
i
|
数字的格式与 strtol 中对 | |||||||||
u
|
数字的格式与 strtoul 中对 | |||||||||
o
|
数字的格式与 strtoul 中对 | |||||||||
x , X |
数字的格式与 strtoul 中对 | |||||||||
n
|
不消耗任何输入。不会增加赋值计数。如果该说明符具有赋值抑制运算符定义,则行为未定义。 | |||||||||
a , A (C++11)e , E f , F g , G |
数字的格式与 strtof 中的期望相同。 |
N/A | N/A | float* |
double* |
N/A | N/A | N/A | N/A | long double* |
p
|
|
N/A | N/A | void** |
N/A | N/A | N/A | N/A | N/A | N/A |
对于除 n 之外的每个转换说明符,不会超过任何指定的字段宽度且符合以下条件的最长输入字符序列将从流中消耗:要么完全符合转换说明符的预期,要么是它将预期的序列的前缀。如果有的话,该消耗序列之后的第一个字符将保持未读。如果消耗序列的长度为零,或者如果消耗序列无法按上述方式转换,则将发生匹配失败,除非文件结尾、编码错误或读取错误阻止了流的输入,在这种情况下,它将是输入失败。
除 [、c 和 n 之外的所有转换说明符在尝试解析输入之前,会消耗并丢弃所有前导空白字符(由调用 isspace 所确定)。这些消耗的字符不计入指定的最大字段宽度。
转换说明符 lc、ls 和 l[ 执行多字节到宽字符的转换,就像通过调用 mbrtowc 并使用一个在转换第一个字符之前初始化为零的 mbstate_t 对象一样。
转换说明符 s 和 [ 始终在匹配的字符之外存储空终止符。目标数组的大小必须至少比指定的字段宽度大 1。使用 %s 或 %[ 而不指定目标数组大小,就像 std::gets 一样不安全。
用于 定长整数类型(int8_t 等)的正确转换规范在头文件 <cinttypes> 中定义(尽管 SCNdMAX、SCNuMAX 等与 %jd、%ju 等同义)。
在每个转换说明符的操作之后有一个 序列点;这允许将多个字段存储在同一个“接收器”变量中。
解析以指数结尾但不带数字的非完整浮点数时,例如使用转换说明符 "100er" 解析 %f,序列 "100e"(可能有效的浮点数的最长前缀)将被消耗,导致匹配错误(消耗的序列无法转换为浮点数),而 "r" 将保持不变。一些现有的实现不遵循此规则,而是回滚以仅消耗 "100",留下 "er",例如 glibc bug 1765。
[edit] 返回值
成功读取的参数数量,或者如果失败,则为 EOF。
[edit] 说明
所有这些函数都至少调用一次 va_arg,在返回后 arg
的值是不确定的。这些函数不调用 va_end,必须由调用者完成。
[edit] 示例
#include <cstdarg> #include <cstdio> #include <iostream> #include <stdexcept> void checked_sscanf(int count, const char* buf, const char *fmt, ...) { std::va_list ap; va_start(ap, fmt); if (std::vsscanf(buf, fmt, ap) != count) throw std::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 (const std::exception& e) { std::cout << e.what() << '\n'; } }
输出
Parsing '1 2'... success Parsing '1 a'... parsing error
[edit] 另请参阅
从 stdin、文件流或缓冲区读取格式化的输入。 (函数) | |
将格式化的输出打印到 stdout、文件流或缓冲区。 使用可变参数列表。 (函数) | |
C 文档 for vscanf, vfscanf, vsscanf
|