以正确的方式将字符串转换为整数

时间:2016-07-20 18:15:17

标签: c++

我想验证字符串是否为有效整数。我可以使用64位整数和函数,如std::stoullstd::stoll,但我无法验证该值是否在给定范围之间。

例如,我想要一个介于0和UINT64_MAX之间的整数。如果字符串为"-1",我可以将其转换为long long,并且我知道它是否定的。但是,如果字符串高于有符号长long (通常为INT64_MAX)的最大值,则溢出会使其再次为负数,而字符串为正整数。

一位朋友首先建议我检查一个减号,但我不喜欢这个解决方案,然后我考虑使用双,但我知道使用双打的比较可能很棘手,所以这就是为什么我不确定这个解决方案。

template <typename T>
inline bool is_between(const string &str,
                       T min = numeric_limits<T>::min(),
                       T max = numeric_limits<T>::max()) noexcept
{
    try {
        double value = stod(str);

        if (value < min || value > max)
            return false;
    } catch (...) {
        return false;
    }

    return true;
}

这个功能安全吗?因为我害怕一串&#34; 1&#34;可以返回&#34; 0.9999999999&#34;的双倍值,然后它将不适合1到100之间的间隔。

然后我们可以使用这样的函数:

cout << is_between<uint16_t>("0") << endl;
cout << is_between<uint16_t>("65535") << endl;
cout << is_between<uint16_t>("65535", 0, 2000) << endl;
cout << is_between<uint16_t>("-1") << endl;
cout << is_between<uint16_t>("800000") << endl;

1 个答案:

答案 0 :(得分:2)

您的函数对于您描述的错误是安全的,因为足够小的整数可以用浮点数精确表示。因此,1的转换不能为0.99999,因为如果0.99999可以用双精度表示,则它们是不同的数字。可以将0.99999转换为1

但是,如果数量足够大,则限制检查不起作用,因为64位双精度对于小数部分而言比64位整数具有更少的位(通常为54,但在标准中未定义)。例如,以下程序的输出为1而不是0,就像它具有更高的精确数一样。

#include <iostream>
#include <string>

int main(){
  long long v=(1l << 54) +1;
  std::cout << v-static_cast<long long>(std::stod(std::to_string(v))) << std::endl;
}

如果您真的需要接近UINT64_MAX的数字,最好使用像Boost multiprecision这样的库。它具有任意精度整数cpp_int,可以从std::string构造。