【问题标题】:How exactly does C++ casting between numeric types work? [duplicate]数字类型之间的 C++ 转换究竟是如何工作的? [复制]
【发布时间】:2014-05-04 08:04:59
【问题描述】:

在我的代码中,我执行以下操作:

double a = 3.0;
uint64_t b = static_cast<uint64_t>(a);
double c = static_cast<double>(b);

有趣的是,只要 a 为正数,这正如我所期望的 (a == c),但如果 a 为负数,c 最终会成为一个任意大的正数。 (它一定是包裹在某个地方或什么地方。)

我的问题是:

  1. 为什么会这样?
  2. 为什么这段代码不违反严格的别名规则?

注意: double 和 uint64_t 在我的系统上大小相同。

【问题讨论】:

    标签: c++ casting double uint64


    【解决方案1】:

    严格的别名只对指针起作用。就像将double * 转换为uint64_t * 并通过该指针访问内存一样,因此您不必在这里担心。阅读What is the strict aliasing rule? 的优秀答案以获取更多信息。

    对于转换,它会尝试将您的double 持有的值转换为uint64_t 可以表示的值。但是uint64_t 是无符号的,不能表示负值,因此在尝试转换负值(也就是过高且无法表示的正值)时,您会得到未定义的行为。在实践中,您可能会得到一些较高的正数,但您不应该依赖它。


    C++ 标准 (N3797) 4.9 [conv.fpint]/1 说:

    浮点类型的纯右值可以转换为 整数类型。转换截断;也就是小数部分 被丢弃。如果截断的值不能,则行为未定义 在目标类型中表示。 [注:如果目的地 类型为布尔型,见 4.12。 ——尾注]

    Chris Dodd 在他的评论中所指的明确定义仅适用于整数转换,不适用于 doubleuint64_t 的浮点转换。

    有关更多信息,我还写了blog post

    【讨论】:

    • 实际上,转换为无符号类型总是定义明确的——你总是会得到模 2^k 的值,其中 k 是无符号类型的大小(以位为单位)。将超出范围的值转换为有符号整数类型会给您一个未定义的值(但不是未定义的行为)
    【解决方案2】:

    uint64_t 表示 64 位 无符号 整数,因此当您转换为 uint64_t 时,如果该数字为负数,则会溢出,因为无符号整数无法存储负数。

    用 int64_t 试试,它会按预期工作。

    【讨论】:

      猜你喜欢
      • 2012-01-26
      • 2019-10-12
      • 1970-01-01
      • 1970-01-01
      • 2015-02-20
      • 2014-01-20
      • 2023-03-16
      • 2012-10-07
      • 2013-02-12
      相关资源
      最近更新 更多