隐式转换双精度到无符号长溢出C++

Pod*_*rce 2 c++ integer-overflow ctime

我正在使用 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;
}
Run Code Online (Sandbox Code Playgroud)

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

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

相反,我期望它首先计算“ticks”/CLOCK_PER_SEC 的双倍值,然后将其转换为无符号长整型。

在尝试计算更多秒数时,我尝试返回 unsigned long long 数据类型,但该变量总是在相同值(2147)处溢出。

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

Bat*_*eba 5

与流行的看法相反,如果值无法适合该整型,则将浮点类型(例如 a)转换double任何整型的行为是未定义的。

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

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