首页 > 解决方案 > std::get_time() 对于“短”输入的正确行为是什么

问题描述

我试图了解当输入数据比格式字符串预期的“短”时,C++11 std::get_time() 的正确行为应该是什么。例如,下面的程序应该打印什么:

#include <ctime>
#include <iomanip>
#include <sstream>
#include <iostream>

int main (int argc, char* argv[])
{
  using namespace std;

  tm t {};
  istringstream is ("2016");
  is >> get_time (&t, "%Y %d");

  cout << "eof:  " << is.eof ()  << endl
       << "fail: " << is.fail () << endl;
}

请注意,get_time() 行为是根据 std::time_get<CharT,InputIt>::get()描述的。基于后者(参见 1c 段),我希望同时设置 eofbit 和 failbit ,因此程序将打印:

eof:  1
fail: 1

但是,对于所有主要的标准 C++ 库实现(libstdc++ 10.2.1、libc++ 11.0.0 和 MSVC 16.8),它会打印:

eof:  1
fail: 0

有趣的是,对于 16.8 之前的 MSVC,它会打印:

eof:  1
fail: 1

但是提交“当格式长于流时,std::get_time 不应失败” 表明这是故意修复的。

有人可以澄清所提到的标准库是否(以及为什么)行为正确,如果是这种情况,它应该如何检测格式字符串未完全使用。

标签: c++11stddate-parsing

解决方案


我无法 100% 准确地解释,但我可以尝试解释为什么函数的行为与观察到的一样。

我怀疑eofbit在你的情况下没有设置,即 1c,因为情况 1b 优先:

b) 出现解析错误 ( err != std::ios_base::goodbit)

根据https://en.cppreference.com/w/cpp/io/ios_base/iostate的 eofbit部分,设置 eof 位的情况之一是

std::get_timeI/O 操纵器和任何解析std::time_get函数:time_get::gettime_get::get_timetime_get::get_date,如果在处理解析预期日期/时间值所需的最后一个字符之前到达流的末尾。

相同的来源failbit说:

如果输入不能根据给定的格式字符串明确地解析为时间值,则时间输入操纵器std::get_time(从技术上讲,它调用)。time_get::get

所以我的猜测是,当输入为 2000 时,get尝试在 using 中读取它operator>>(std::string&),达到 eof 条件并设置eofbit. 这满足条件 1b,因此不能应用条件 1c。

如果函数需要年份并且输入小于 4 位,例如200,或者它在年份之后包含一个空格2000 ,或者包含多于 4 位,20001则函数返回failbit。但是,如果输入是一个以 0 开头的 4 位数字,例如0005,则函数返回eofbit== 1, failbit == 0。这符合%Y格式说明符的规范:

将全年解析为 4 位十进制数,允许但不需要前导零

所以我希望这能解释为什么有时不考虑条件 1c。good()我们可以通过测试成员函数来检测到格式字符串没有以通常的方式被完全使用。我相信告诉函数返回 == 1 或 0 之间的区别failbit几乎没有实际意义。我也认为这里的标准不精确,但如果我们假设用户对 的值感兴趣,那么good()这种缺乏精确性就没有实际意义。

在您考虑的情况下, 的值也可能failbit是实现定义的:实现可以尝试准确读取 4 个字符以满足%Y格式说明符,在这种情况下eofbit不会设置 。但这只是我的猜测。

编辑 看看你的程序的这个修改:

int main (int argc, char* argv[])
{
  using namespace std;

  tm t {};
  istringstream is ("2016");
//  is >> get_time (&t, "%Y %d");
  std::string s;
  is >> s;

  cout << "eof:  " << is.eof ()  << endl
       << "fail: " << is.fail () << endl;
}

我替换get_timestd::string,但行为没有改变!字符串已读完,因此流状态不能设置为fail; 但是,它到达了文件末尾,所以eofbit已经设置了!

eof:1
失败:0

我的意思是,类似的现象可以在内部发生get_time,然后流的状态传播到get_time.


推荐阅读