61

我的问题是

我有一个 size_t 数据,但现在我想将其转换为 double 或 int。

如果我做类似的事情

 size_t data = 99999999;
 int convertdata = data;

编译器将报告警告。因为它可能会溢出。

您是否有某种方法(例如 boost 或其他方法)来进行转换?

4

5 回答 5

88

正如 Blaz Bratanic 所建议的那样:

size_t data = 99999999;
int convertdata = static_cast<int>(data);

可能会使警告静音(尽管原则上编译器可以警告它喜欢的任何东西,即使有演员表)。

但这并不能解决警告告诉您的问题,即从size_tto的转换int真的可能溢出。

如果可能,请设计您的程序,这样您就不需要size_t值转换为int. 只需将其存储在一个size_t变量中(正如您已经完成的那样)并使用它。

转换为double不会导致溢出,但可能会导致非常大的size_t值的精度损失。size_t同样,将 a 转换为 a没有多大意义double;您最好将值保存在size_t变量中。

(如果您无法避免强制转换, R Sahu 的回答有一些建议,例如在溢出时抛出异常。)

于 2014-03-04T22:30:01.890 回答
22

如果您的代码准备好处理溢出错误,那么如果data太大,您可以抛出异常。

size_t data = 99999999;
if ( data > INT_MAX )
{
   throw std::overflow_error("data is larger than INT_MAX");
}
int convertData = static_cast<int>(data);
于 2014-03-04T22:37:40.723 回答
18

静态演员表:

static_cast<int>(data);
于 2014-03-04T22:24:18.163 回答
12

您可以使用 Boost numeric_cast

如果源值超出目标类型的范围,则会引发异常,但在转换为double.

size_t但是,无论您使用什么函数,您都应该决定在 中的值大于的情况下要发生什么INT_MAX。如果您想检测它,请使用numeric_cast或编写自己的代码进行检查。如果您以某种方式知道它不可能发生,那么您可以使用static_cast来抑制警告而无需运行时检查,但在大多数情况下,成本无论如何都无关紧要。

于 2014-03-04T23:32:46.200 回答
4

假设无法重新设计程序以避免演员表(参考Keith Thomson 的回答):

要从 size_t 转换为 int,您需要确保 size_t 不超过 int 的最大值。这可以使用std::numeric_limits来完成:

int SizeTToInt(size_t data)
{
    if (data > std::numeric_limits<int>::max())
        throw std::exception("Invalid cast.");
    return std::static_cast<int>(data);
}

如果您需要从 size_t 转换为 double,并且需要确保不会丢失精度,我认为您可以使用窄转换(参考 Stroustrup:C++ 编程语言,第四版):

template<class Target, class Source>
Target NarrowCast(Source v)
{
    auto r = static_cast<Target>(v);
    if (static_cast<Source>(r) != v)
        throw RuntimeError("Narrow cast failed.");
    return r;
}

我通过检查最大整数浮点可表示整数的限制(代码使用 googletest)来测试 size_t 到双精度转换的窄转换:

EXPECT_EQ(static_cast<size_t>(NarrowCast<double>(size_t{ IntegerRepresentableBoundary() - 2 })), size_t{ IntegerRepresentableBoundary() - 2 });
EXPECT_EQ(static_cast<size_t>(NarrowCast<double>(size_t{ IntegerRepresentableBoundary() - 1 })), size_t{ IntegerRepresentableBoundary() - 1 });
EXPECT_EQ(static_cast<size_t>(NarrowCast<double>(size_t{ IntegerRepresentableBoundary() })), size_t{ IntegerRepresentableBoundary() });
EXPECT_THROW(NarrowCast<double>(size_t{ IntegerRepresentableBoundary() + 1 }), std::exception);
EXPECT_EQ(static_cast<size_t>(NarrowCast<double>(size_t{ IntegerRepresentableBoundary() + 2 })), size_t{ IntegerRepresentableBoundary() + 2 });
EXPECT_THROW(NarrowCast<double>(size_t{ IntegerRepresentableBoundary() + 3 }), std::exception);
EXPECT_EQ(static_cast<size_t>(NarrowCast<double>(size_t{ IntegerRepresentableBoundary() + 4 })), size_t{ IntegerRepresentableBoundary() + 4 });
EXPECT_THROW(NarrowCast<double>(size_t{ IntegerRepresentableBoundary() + 5 }), std::exception);

在哪里

constexpr size_t IntegerRepresentableBoundary()
{
    static_assert(std::numeric_limits<double>::radix == 2, "Method only valid for binary floating point format.");
    return size_t{2} << (std::numeric_limits<double>::digits - 1);
}

也就是说,如果 N 是尾数中的位数,对于小于或等于 2^N 的双精度数,可以精确表示整数。对于 2^N 和 2^(N+1) 之间的双精度数,可以精确表示每隔一个整数。对于 2^(N+1) 和 2^(N+2) 之间的双精度数,可以精确表示每四个整数,依此类推。

于 2017-02-27T07:51:21.277 回答