【问题标题】:istringstream not honoring base?istringstream 不尊重基地?
【发布时间】:2015-11-14 12:19:34
【问题描述】:

由于使用了atoiatof,我正在尝试修复一些关于受污染值的 Coverity 调查结果。我切换到istringstream,但它不会为 10 以外的碱基产生预期结果。

如果我切换到base 16,输入0xa并避开iss.ignore(2);,那么结果是0:

$ ./tt.exe 0xa
X: 0

如果我切换到base 16,输入0xa并使用iss.ignore(2);,那么结果是一个异常:

$ ./tt.exe 0xa
'0xa' is not a value

我按照@πάντα 的推荐访问了CPP Reference on istringstream,但它没有讨论这种情况下的限制。

任何想法我做错了什么?或者,我怎样才能让它按预期工作?


$ cat tt.cxx
#include <iostream>
#include <sstream>
#include <iomanip>
#include <stdexcept>
using namespace std;

template <class T>
T StringToValue(const std::string& str) {
  std::istringstream iss(str);
  T value;

  if (str.length() >= 2) {
    if (str[0] == '0' && (str[1] =='X' || str[1] =='x'))
      {
        iss.setf(std::ios_base::hex);
        iss.ignore(2);
      }
  }
  iss >> value;

  if (iss.fail())
    throw runtime_error("'" + str +"' is not a value");

  return value;
}

int main(int argc, char* argv[])
{
  try
    {
      int x = StringToValue<int>(argc >= 2 ? argv[1] : "ZZZ...");
      cout << "X: " << x << endl;
    }
  catch(const runtime_error& ex)
    {
      cerr << ex.what() << endl;
      return 1;
    }

  return 0;
}

【问题讨论】:

  • 读入数字时去掉0x前缀。
  • 啊,我明白了,你已经把ignore(2)放在那里了。
  • 通常的方式是iss &gt;&gt; hex &gt;&gt; value;
  • 你能做一个minimal测试用例吗?
  • @user1034749 - 我们支持古老的编译器。事实上,我刚刚用 GCC 3.2 在 Fedora 1 上完成了测试。 (我们不像浏览器和苹果操作系统)。

标签: c++ base istream


【解决方案1】:

你完全想多了。读取十六进制值很容易。

#include <sstream>
#include <iomanip>
#include <cassert>

int main()
{
   {
      int x = 0;
      std::istringstream is("0xa");
      is >> std::hex >> x;
      assert(x == 10);
   }
   {
      int x = 0;
      std::istringstream is("a");
      is >> std::hex >> x;
      assert(x == 10);
   }
}

(live demo)


无论如何,我可以确定您的代码存在两个问题。

1。错误使用std::ios_base::setf

您正在用 only std::ios_base::hex 替换流的整个标志集。这些标志不仅适用于数字基数。为此,您需要屏蔽其他所有内容,以防止取消设置其他不相关但必要的标志(我不知道它们是什么):

iss.setf(std::ios_base::hex, std::ios::basefield);

这就是iss &gt;&gt; std::hex 如此简单的原因。

这也是为什么您应该在发布之前构建一个由只包含iss.setf 的测试的最小测试用例!

2。逻辑不通

输入只是“a”的情况完全跳过该语句,因为它的条件是前两个字符为“0x”。

我想把它移到iss &gt;&gt; value之前。


您可以看到您的固定代码 here,但正如我在回答开头所探讨的那样,整个 switch-on-leading-"0x" 事情是不必要的,因此您的大部分代码都可以删除。

【讨论】:

  • 谢谢。任何想法为什么明确设置基础没有按预期工作?将来可能会对我有所帮助。
  • @jww:我没有调查。现在我已经用一个最小的测试用例证明istringstream 工作得很好,你可以继续调试来找出答案。 :)
  • 看起来它也可以帮助其他人:Get precision of cout。再次感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-30
  • 2014-02-27
  • 1970-01-01
  • 2011-04-30
相关资源
最近更新 更多