隐式转换 double 到 unsigned long 溢出 c++

Implicit conversion double to unsigned long overflow c++

我正在使用 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() return 计算值时,我正在执行从 double 到 unsigned long 的隐式转换。 32 位系统的无符号长限制为 2,147,483,647,我在 Elapsed() returns 2146.

后溢出

看起来函数将 "ticks" 转换为 unsigned long,将 CLOCK_PER_SEC 转换为 unsigned long,然后它 return 是值。当它转换 "ticks" 时它会溢出。

我希望它首先计算 "ticks"/CLOCK_PER_SEC 的双倍值,然后将其转换为无符号长整数。

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

你能解释一下为什么编译器转换为 unsigned long long "a priori" 以及为什么即使使用 unsigned long long 它也会在相同的值处溢出吗? 有什么方法可以更好地编写 Elapsed() 函数以防止发生溢出?

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

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

如果可以允许截断和环绕效果,为什么不写成 return ticks / CLOCKS_PER_SEC;?或者,如果不是,请使用 unsigned long long 作为 return 值。

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

When it converts the "ticks" it overflows.

不,时钟本身"overflows";转换与它无关。也就是说,转换为 double 是没有意义的。您的限制是 clock_t 类型。请参阅此 reference:

中的注释示例

The value returned by clock() may wrap around on some implementations. For example, on a machine with 32-bit clock_t, it wraps after 2147 seconds or 36 minutes.

一种替代方法(如果您可以的话)是依赖 POSIX 标准而不是 C 标准库。它提供 clock_gettime which can be used to get the CPU time represented in timespec。它不仅不会受到这种溢出的影响(直到更长的时间跨度),而且它的分辨率也可能比 clock 更高。 clock() 的链接参考页面也方便地显示了 clock_gettime 的示例用法。