使用std::istream_iterator<float>读取超范围数值是否为未定义行为?
超范围浮点数输入的行为判定
测试代码
const std::string str = "-5.73945e-39"; std::istringstream iss(str); auto vals = std::vector<float>(std::istream_iterator<float>(iss), std::istream_iterator<float>{});
现象描述
这段代码在搭载M1芯片的Mac上使用Apple clang 15.0.0(clang-1500.0.16.10)编译运行时,vals的大小为0;但在其他编译器环境中运行时,vals的大小为1。显然-5.73945e-39超出了标准float的常规可表示范围(标准float最小正规格化值约为1.17549e-38)。
行为性质判定
这种情况不属于未定义行为,而是实现定义的行为,具体依据如下:
- 根据C++标准,当输入浮点数超出目标类型的有限值范围时,若类型支持无穷大,会将值设为对应正负无穷大,且不置位流的
failbit; - 若输入值小于类型的最小正规格化值(即下溢),实现可选择将值舍入到0,或设置为最小非规格化值,这属于标准允许的实现定义行为;
- 若输入值完全超出类型能表示的极限(包括非规格化范围),实现可以置位流的
failbit,导致输入操作失败,这也是标准允许的行为。
在你的例子中,-5.73945e-39远小于float的最小正规格化值:
- Apple clang的实现选择触发
failbit,使istream_iterator停止读取,因此vals大小为0; - 其他编译器的实现可能将该值舍入到0,输入操作成功,因此
vals大小为1。
两种表现均符合C++标准的规范,属于实现定义的行为,而非未定义行为。
内容的提问来源于stack exchange,提问作者Yifu
相关产品推荐
相关产品推荐

