【问题标题】:So, we have int32_t, int16_t, uint64_t, etc.. But where are the atoi32, atoi16, atoui64, etc...?所以,我们有 int32_t、int16_t、uint64_t 等。但是 atoi32、atoi16、atoui64 等在哪里?
【发布时间】:2012-01-23 19:39:24
【问题描述】:

我想将表示数字的字符串输入转换为相应的数字类型。问题是我有严格的类型要求,因此,例如,我不能接受 x >= 2^15 ,其中需要 int16_t 值(有符号)。

在不从头编写所有转换函数的情况下,如何处理这种情况?

附言

请不要建议boost::lexical_cast - 我已经在使用它了。我所说的函数将通过特定的模板特化来替换lexical_cast 模板的默认实现,即:

template<>
inline int32_t lexical_cast<int32_t,char const *>(const char * const & arg)
{
}
template<>
inline int16_t lexical_cast<int16_t,char const *>(const char * const & arg)
{
}
...

理想情况下,拥有atoi32、atoi16、atoiu64 等函数会很好......

编辑

我正在使用 VS2010,所以 &lt;cinttypes&gt; 运气不好。

是的,如果有一个改进的atoi 系列函数具有与strtol 相同的错误支持,那就太好了。

EDIT2

认为值得发布我的解决方案:

#pragma once

#include <boost/lexical_cast.hpp>
#include <limits>

namespace boost {

template<class TInt, class conv>
TInt atoi(conv f, const char *arg)
{
  char* stop;
  TInt res = f(arg, &stop, 10);
  if (*stop)
  {
    throw_exception(bad_lexical_cast(typeid(TInt), typeid(const char *)));
  }
  return res;
}

template<class TInt>
typename std::enable_if<std::is_signed<TInt>::value, TInt>::type atoi(const char *arg)
{
  char* stop;
  long res = strtol(arg, &stop, 10);
  if (*stop || std::numeric_limits<TInt>::min() > res || std::numeric_limits<TInt>::max() < res)
  {
    throw_exception(bad_lexical_cast(typeid(TInt), typeid(const char *)));
  }
  return (TInt)res;
}

template<class TInt>
typename std::enable_if<std::is_unsigned<TInt>::value, TInt>::type atoi(const char *arg)
{
  char* stop;
  unsigned long res = strtoul(arg, &stop, 10);
  if (*stop || std::numeric_limits<TInt>::max() < res)
  {
    throw_exception(bad_lexical_cast(typeid(TInt), typeid(const char *)));
  }
  return (TInt)res;
}

template<> inline int8_t lexical_cast<int8_t,char const *>(const char * const & arg)
{
  return atoi<int8_t>(arg);
}

template<> inline uint8_t lexical_cast<uint8_t,char const *>(const char * const & arg)
{
  return atoi<uint8_t>(arg);
}

template<> inline int16_t lexical_cast<int16_t,char const *>(const char * const & arg)
{
  return atoi<int16_t>(arg);
}

template<> inline uint16_t lexical_cast<uint16_t,char const *>(const char * const & arg)
{
  return atoi<uint16_t>(arg);
}

template<> inline int32_t lexical_cast<int32_t,char const *>(const char * const & arg)
{
  return atoi<int32_t>(strtol, arg);
}

template<> inline uint32_t lexical_cast<uint32_t,char const *>(const char * const & arg)
{
  return atoi<uint32_t>(strtoul, arg);
}

template<> inline int64_t lexical_cast<int64_t,char const *>(const char * const & arg)
{
  return atoi<int64_t>(_strtoi64, arg);
}

template<> inline uint64_t lexical_cast<uint64_t,char const *>(const char * const & arg)
{
  return atoi<uint64_t>(_strtoui64, arg);
}

template<> inline double lexical_cast<double,char const *>(const char * const & arg)
{
  char* stop;
  double res = strtod(arg, &stop);
  if (*stop)
  {
    throw_exception(bad_lexical_cast(typeid(double), typeid(const char *)));
  }
  return res;
}

template<> inline float lexical_cast<float,char const *>(const char * const & arg)
{
  char* stop;
  double res = strtod(arg, &stop);
  if (*stop || -FLT_MAX > res || FLT_MAX < res)
  {
    throw_exception(bad_lexical_cast(typeid(float), typeid(const char *)));
  }
  return res;
}

}

所以,最后我使用的是strtol 系列函数。不幸的是,建议使用它们的人也删除了他的帖子,我想知道为什么......

【问题讨论】:

  • 有strol和strtoll,strtoq。
  • 有atoi、atol、atoll,就够了,因为你提到的所有类型都可以转换为long long或int而不会出现溢出问题
  • 那些是类型定义。如果你专门或重载 typedef,你会大吃一惊!
  • @mark,我可以问一下你想要这些功能的真正原因(除了漂亮)吗? ato* 家族在我看来总是很破碎,因为他们返回 0 合法的 0 和错误的输入。
  • 你是对的。 strtol 的错误支持应该被 atoi 系列函数所接受。

标签: c++ c++11


【解决方案1】:

scanf 系列 &lt;cstdio&gt; 函数实现了所有必需的转换,&lt;cinttypes&gt;(在 C++11 中;&lt;inttypes.h&gt; 在与 C99 库相结合的 C++98 编译器中)定义了适当的格式字符串说明符。例如,要从 C 字符串 s 中读取 int16_t,请执行

int16_t i;
std::sscanf(s, "%"SCNd16, &i);

【讨论】:

  • Visual Studio 不支持这些。 VS2010中没有cinttypes头文件。
  • @mark:在 C++11 之前的编译器中,int16_t 也不需要。您可以从各种来源获得替换 inttypes.h,例如code.google.com/p/msinttypes.
  • 你想说我可以只定义SCNXXX宏吗?他们的价值观是否被 VS2010 认可?
  • @mark:它们只是扩展为正确格式字符串的宏,例如SVNd16 在 VC++ 中会扩展为 "hd",因为 int16_t 是 typedef 的 signed short。
猜你喜欢
  • 2014-12-24
  • 1970-01-01
  • 1970-01-01
  • 2011-11-14
  • 1970-01-01
  • 2015-09-22
  • 1970-01-01
  • 2019-05-13
  • 2013-10-24
相关资源
最近更新 更多