示例代码at Coliru:
#include <iostream>
#include <sstream>
#include <string>
int main()
{
double d; std::string s;
std::istringstream iss("234cdefipxngh");
iss >> d;
iss.clear();
iss >> s;
std::cout << d << ", '" << s << "'\n";
}
我在这里阅读N3337(可能与C ++ 11相同)。在[istream.formatted.arithmetic]中我们有(释义):
operator>>(double& val);
与插入器的情况一样,这些提取器依赖于语言环境的num_get&lt;&gt; (22.4.2.1)对象 执行解析输入流数据。这些提取器表现为格式化的输入函数(如 在27.7.2.2.1中描述。构造sentry对象后,转换就像执行以下代码片段一样:
typedef num_get< charT,istreambuf_iterator<charT,traits> > numget;
iostate err = iostate::goodbit;
use_facet< numget >(loc).get(*this, 0, *this, err, val);
setstate(err);
查看22.4.2.1:
此操作的详细信息分三个阶段发生 - 阶段1:确定转换说明符
- 阶段2:从中提取字符并确定格式的相应字符值 由第1阶段确定的转换规范预期。
- 第3阶段:存储结果
在第2阶段的描述中,对我来说,将整个事情粘贴在这里太长了。但是它清楚地表明在尝试转换之前应该提取所有字符;而且应该提取以下字符:
0123456789abcdefxABCDEFX+-
decimal_point()
thousands_sep()
最后,第3阶段的规则包括:
- 对于浮点值,函数
strtold
。要存储的数值可以是以下之一:
- 如果转换函数无法转换整个字段,则为零。
这似乎清楚地指明了我的代码的输出应该是0, 'ipxngh'
。但是,它实际上输出了其他东西。
这是编译器/库的错误吗?我是否有任何规定可以忽略某个地方以改变第2阶段的行为? (在another question中有人发布了一个实际提取字符的系统示例,但也提取了不在N3337中指定的列表中的ipxn
。
正如虚幻所指出的,第2阶段的文本是相关的:
如果discard为true,那么如果'。'尚未累积,那么该字符的位置 被记住,但这个角色被忽略了。否则,如果'。'已经存在 累积后,角色被丢弃,第2阶段终止。如果没有丢弃,那么a 检查是否允许
c
被允许作为阶段1返回的转换说明符的输入字段的下一个字符。如果是,则累计。如果该字符被丢弃或累积,那么在++中进行处理 回到第2阶段的开头。
因此,如果角色位于允许的字符列表中,则第2阶段可以终止,但不是%g
的有效字符。它没有确切地说,但可能这是指C99中fscanf
的定义,它允许:
- 非空的十进制数字序列,可选地包含小数点 字符,然后是6.4.4.2中定义的可选指数部分;
- 一个0x或0X,然后是一个非空的十六进制数字序列,可选地包含一个 小数点字符,然后是6.4.4.2;
中定义的可选二进制指数部分- INF或INFINITY,忽略大小写
- NAN或NAN(n-char-sequence opt),忽略NAN部分中的情况,其中:
以及
除了&#34; C&#34;语言环境,可以接受其他特定于语言环境的主题序列表单。
所以,实际上Coliru输出是正确的;事实上,处理必须尝试验证提取的字符序列,直到%g
的有效输入,同时提取每个字符。
下一个问题:在我之前链接的主题中,是否允许在第2阶段接受i
,n
,p
等?
这些是%g
的有效字符,但它们不在允许第2阶段读取的原子列表中(即c == 0
表示我的最新引号,因此字符既不丢弃也不累积)。
答案 0 :(得分:5)
这很乱,因为很可能gcc / libstdc ++和clang / libc ++的实现都不符合要求。目前还不清楚“检查是否允许c作为第1阶段返回的转换说明符的输入字段的下一个字符”是指,但我认为使用短语“next character”表示检查应该是上下文敏感(即,取决于已经累积的字符),因此在遇到"21abc"
时应该停止尝试解析,例如'a'
。这与LWG issue 2041中的讨论是一致的,它在C ++ 11的起草过程中删除后将该句子添加回标准。 libc ++没有这样做是bug 17782。
"0xABp-4"
超过0
,这实际上显然是基于标准的不一致(它应该将"0xAB"
解析为hexfloat,显然C99 fscanf
规范允许%g
。
标准不允许接受i
,p
和n
。请参阅LWG issue 2381。
标准非常精确地描述了处理 - 它必须由指定的代码片段“完成”完成,它不接受这些字符。比较LWG issue 221的分辨率,其中x
和X
添加了num_get
和0x
,因为{{1}}正如后面描述的那样不会解析{{1}}对于整数输入。
Clang / libc ++接受“inf”和“nan”以及hexfloats但不接受“infinity”作为扩展。请参阅bug 19611。
答案 1 :(得分:4)
在第2阶段结束时,它说:
如果没有丢弃,则进行检查以确定c是否为 允许作为转换输入字段的下一个字符 第1阶段返回的指定者。如果是,则累积。
如果该字符被丢弃或累积,则in进入++ in并且处理返回到第2阶段的开头。
因此,a
说明符中不允许%g
,并且不会累积或忽略它。