【问题标题】:Implicit conversion double to unsigned long overflow c++将double隐式转换为无符号长溢出c ++
【发布时间】:2018-12-10 10:06:24
【问题描述】:

我正在使用clock() 函数测试基于ctime 库的计时器。 请注意,以下代码仅用于测试目的。

#include <ctime>

unsigned long Elapsed(void);

clock_t start = 0;
clock_t stop = 0;

int main()
{
  start = std::clock();
  while(1)
   {
    sleep(1);
    cout << "Elapsed seconds: " << Elapsed() << endl;
   }
return 0;
}

unsigned long Elapsed()
{
  stop = std::clock();
  clock_t ticks = stop - start;
  double seconds = (double)ticks / CLOCKS_PER_SEC;  //CLOCK_PER_SEC = 1 milion
  return seconds;
}

如您所见,当 Elapsed() 返回计算值时,我正在执行从 double 到 unsigned long 的隐式转换。 32 位系统的无符号长限制为 2,147,483,647,并且在 Elapsed() 返回 2146 后出现溢出。

看起来该函数将“ticks”转换为 unsigned long,CLOCK_PER_SEC 转换为 unsigned long,然后返回值。当它转换“刻度”时,它会溢出。

相反,我希望它首先计算 "ticks"/CLOCK_PER_SEC 的 double 值,然后将其转换为 unsigned long。

为了计算更多秒数,我尝试返回一个 unsigned long long 数据类型,但变量总是以相同的值 (2147) 溢出。

您能否解释一下为什么编译器会转换为 unsigned long long “先验”以及为什么即使使用 unsigned long long 它也会以相同的值溢出? 有没有什么方法可以更好地编写 Elapsed() 函数来防止溢出发生?

【问题讨论】:

  • unsigned long 对于 32 位系统的限制是 4294967295,它是 std::clock(),每 2147 秒循环一次:en.cppreference.com/w/cpp/chrono/c/clock 所以seconds 是一个介于 0 和2147,所以隐式转换为unsigned long 就可以了。
  • @M.M 已编辑,抱歉。

标签: c++ integer-overflow ctime


【解决方案1】:

与流行的看法相反,将浮点类型(例如 double)转换为 any 整数类型的行为是 undefined 如果值不能适合该整数输入。

所以在你的函数中引入double 确实是一件糟糕的事情。

如果可以允许截断和环绕效果,为什么不写 return ticks / CLOCKS_PER_SEC; 呢?如果没有,则使用unsigned long long 作为返回值。

【讨论】:

    【解决方案2】:

    如果在您的系统上,clock_t 是 32 位类型,那么它很可能会像您看到的那样在 2147 秒后回绕。这是预期的行为(参考clock)。再多的演员也无法解决这个问题。您的代码需要能够处理环绕(通过忽略它,或者通过明确考虑它)。

    【讨论】:

      【解决方案3】:

      当它转换“刻度”时,它会溢出。

      不,时钟本身“溢出”;转换与它无关。也就是说,转换为double 毫无意义。您的限制是clock_t 类型。请参阅此 reference 中的注释:

      clock() 返回的值可能会在某些实现中回绕。例如,在具有 32 位 clock_t 的机器上,它会在 2147 秒或 36 分钟后换行。

      如果您可以使用,另一种选择是依赖 POSIX 标准而不是 C 标准库。它提供了clock_gettime,可用于获取timespec 中表示的CPU 时间。它不仅不受这种溢出的影响(直到更长的时间跨度),而且它的分辨率也可能比clock 更高。 clock() 的链接参考页面也方便地显示了clock_gettime 的示例用法。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-07-23
        • 2014-01-07
        • 1970-01-01
        • 1970-01-01
        • 2016-05-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多