由istream >> double提取的字符

M.M*_*M.M 6 c++ iostream facets c++11

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";
}
Run Code Online (Sandbox Code Playgroud)

我在这里读N3337(可能与C++ 11相同).在[istream.formatted.arithmetic]中我们有(释义):

operator>>(double& val);

与插入器的情况一样,这些提取器依赖于语言环境的num_get <>(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 阶段中确定的转换规范所期望格式的相应char值.
- 阶段3:存储结果

在阶段2的描述中,对我来说,将整个事情粘贴在这里太长了.但是它清楚地表明在尝试转换之前应该提取所有字符; 而且应该提取以下字符:

  • 任何 0123456789abcdefxABCDEFX+-
  • 当地的 decimal_point()
  • 当地的 thousands_sep()

最后,第3阶段的规则包括:

- 对于浮点值,该函数strtold.

要存储的数值可以是以下之一:

- 如果转换函数无法转换整个字段,则为零.

这似乎都清楚地指明了我的代码的输出应该是0, 'ipxngh'.但是,它实际上输出了其他东西.

这是编译器/库的错误吗?是否有任何条款我忽略了一个区域设置来改变第二阶段的行为?(在另一个问题中,有人发布了一个实际提取字符的系统示例,但也提取了ipxn不在N3337中指定的列表中的提取).

更新

正如虚幻所指出的,第2阶段的文本是相关的:

如果丢弃是真的,那么如果'.' 尚未累积,然后记住角色的位置,但否则角色会被忽略.否则,如果'.' 已经累积,角色被丢弃,第2阶段终止.如果它没有被丢弃,则进行检查以确定是否c允许作为阶段1返回的转换说明符的输入字段的下一个字符.如果是,则累积它.

如果该字符被丢弃或累积,则in进入++ in并且处理返回到阶段2的开头.

因此,如果字符在允许字符列表中,但不是有效字符,则阶段2可以终止%g.它没有确切地说,但可能这是指fscanfC99 的定义,它允许:

  • 一个非空的十进制数字序列,可选地包含一个小数点字符,然后是6.4.4.2中定义的可选指数部分;
  • 一个0x或0X,然后是一个非空的十六进制数字序列,可选地包含一个小数点字符,然后是6.4.4.2中定义的可选二进制指数部分;
  • INF或INFINITY,忽略大小写
  • NAN或NAN(n-char-sequence opt),忽略NAN部分的情况,其中:

并且

除了"C"语言环境之外,可以接受其他特定于语言环境的主题序列表单.

所以,实际上Coliru输出是正确的; 事实上,处理必须尝试验证提取的字符序列,直到有效输入为止%g,同时提取每个字符.

下一个问题:这是允许的,因为在线程我挂早些时候,接受i,n,p等在第2阶段?

这些是有效字符%g,但它们不在允许第2阶段读取的原子列表中(即c == 0对于我的最新引用,因此字符既不丢弃也不累积).

T.C*_*.C. 5

这是一团糟,因为gcc/libstdc ++和clang/libc ++的实现都不一致.目前还不清楚"检查是否允许c作为第1阶段返回的转换说明符的输入字段的下一个字符"是指,但我认为使用短语"next character"表示检查应该是上下文敏感(即,取决于已经累积的字符),因此例如,"21abc"'a'遇到时应该停止解析.这与LWG问题2041中的讨论是一致的,该问题在C++ 11的起草过程中删除后将该句子添加回标准.libc ++没有这样做是错误17782.

另一方面,libstdc ++拒绝解析"0xABp-4"过去0,实际上它基于标准显然是不一致的(它应该解析"0xAB"为hexfloat,正如C99 fscanf规范明确允许的那样%g).

的接受i,p以及n不受标准允许的.见LWG第2381期.

该标准非常精确地描述了处理 - 它必须由指定的代码片段"仿佛"完成,它不接受这些字符.比较它们添加的LWG问题221的分辨率xX字符列表,因为num_get如下所述不会解析0x整数输入.

Clang/libc ++接受"inf"和"nan"以及hexfloats但不接受"infinity"作为扩展.见错误19611.