由 istream 提取的字符>>双倍
Characters extracted by istream >> double
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。[算术]我们有(意译):
operator>>(double& val);
与插入器的情况一样,这些提取器依赖于区域设置的num_get<>(22.4.2.1)对象执行输入流数据的解析。这些提取器表现为格式化的输入函数(如见27.7.2.2.1)。在构造哨兵对象之后,转换就像由以下代码片段执行一样:
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:确定转换说明符
-第二阶段:从in中提取字符,并确定相应的字符值阶段1中确定的转换规范所期望的。
-阶段3:存储结果
在第二阶段的描述中,我太长了,不能全部粘贴在这里。然而,它清楚地说,在尝试转换之前应该提取所有字符;此外,应该提取以下字符:
- 任意
0123456789abcdefxABCDEFX+-
区域设置的
decimal_point()
区域设置的thousands_sep()
-对于浮点数,函数
strtold
.要存储的数值可以是:
- 0,如果转换函数转换整个字段失败。
这些似乎都清楚地指定了我的代码的输出应该是0, 'ipxngh'
。但是,它实际上输出了其他内容。
这是编译器/库错误吗?是否有任何规定,我忽略了一个地区,以改变阶段2的行为?(在另一个问题中,有人发布了一个系统的例子,该系统确实提取了字符,但也提取了不在N3337中指定的列表中的ipxn
)。
perreal指出,第二阶段的这段文字是相关的:
如果discard为真,则If '。’尚未积累,则地位的性格会被记住,但角色会被忽略。否则,if '。已经是。累积,角色被丢弃,第二阶段结束。如果没有被丢弃,则a检查是否允许
c
作为阶段1返回的转换说明符的输入字段的下一个字符。如果是,则为累积。如果字符被丢弃或累积,则在前面加++in和处理返回到第2阶段的开始。
因此,如果该字符在允许的字符列表中,但不是%g
的有效字符,则阶段2可以终止。它没有确切地说,但可能指的是C99中fscanf
的定义,它允许:
- 非空的十进制数字序列,可选地包含一个小数点字符,然后是一个可选的指数部分,定义在6.4.4.2;
- 一个0x或0x,然后是一个十六进制数字的非空序列,可选地包含一个小数点字符,然后是6.4.4.2中定义的可选二进制指数部分;
- INF∞,忽略大小写
- NAN或NAN(n-char-sequence opt),忽略NAN部分的大小写,其中
和
除了"C"语言环境,还可以接受其他特定于语言环境的主题序列形式。
所以,实际上Coliru的输出是正确的;事实上,处理必须在提取每个字符时,尝试验证提取到%g
的有效输入的字符序列。
下一个问题:是否允许,就像我之前链接到的线程一样,在第二阶段接受i
, n
, p
等?
这些是%g
的有效字符,但是它们不在阶段2允许读取的原子列表中(即我最近引用的c == 0
,因此该字符既不会被丢弃也不会累积)。
这是一个混乱,因为很可能gcc/libstdc++和clang/libc++的实现都不符合。尚不清楚"检查以确定c是否被允许作为第1阶段返回的转换说明符的输入字段的下一个字符"的意思,但我认为短语"下一个字符"的使用表明检查应该是上下文敏感的(即,依赖于已经积累的字符),因此尝试解析,例如"21abc"
,应该在遇到'a'
时停止。这与LWG第2041期的讨论是一致的,在c++ 11起草期间删除了这句话之后,LWG又将这句话添加到了标准中。libc++的错误是17782。
libstdc++拒绝解析超过0
的"0xABp-4"
,这实际上显然是不符合标准的(它应该将"0xAB"
解析为十六进制浮点数,C99 fscanf
规范明确允许%g
)。
标准不允许接收i
, p
, n
。参见LWG issue 2381。
标准非常精确地描述了处理过程——它必须由指定的代码片段"好像"完成,而代码片段不接受这些字符。比较LWG第221期的分辨率,其中他们将x
和X
添加到字符列表中,因为当时描述的num_get
不会解析0x
的整数输入。
Clang/libc++接受"inf"answers"nan"以及十六进制数,但不接受"infinity"作为扩展名。参见bug 19611。
在第二阶段结束时,它说:
如果没有被丢弃,则检查c是否被丢弃允许作为转换输入字段的下一个字符阶段1返回的说明符。如果是,则为累积。
如果该字符被丢弃或累积,则in被++in推进,处理返回到阶段2的开始。
所以也许a
在%g
说明符中是不允许的,它不会被累积或忽略。
- 我想知道长双倍和双倍之间的区别
- <T> 通过模板化运算符重载将 std::complex 乘以双倍
- 按值 C++ 返回时进行双倍移动
- 求和 int 乘以双倍时的欠/过近似
- 从'size_t'转换为"常量双倍",可能会丢失数据
- 二叉搜索不收敛为双倍
- 将一个双倍值乘以10会发生什么
- 将非常大的 int 转换为双倍,在某些计算机上会损失精度
- 双吨级 - 从单级过渡到双倍级
- 如何将包含指数的 QString 转换为C++中的双倍?
- 防止在字符数组中输入双倍空格在 C++
- 将双倍转换为 LPARAM 的麻烦
- 现代计算机上的双倍和浮点内存分配
- 将 CSV 文件中的双倍值C++到矢量中
- 假设 a 是双倍的,2.0*a 比 2*a 快吗?
- 双倍、长双、浮子和浮子的比较128?
- 是新的(&*p)双倍;一个无操作。因此,uninitialized_default_construct是否也变得无操作?
- 如何将标准::string_view转换为双倍?
- 动态数组的双倍大小
- 错误:无法在赋值中将"双 ()(双)抛出 ()"转换为"双倍"