隐式转换为无符号长溢出C ++

时间:2018-07-02 08:18:29

标签: 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;
}

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

函数似乎将“ ticks”转换为无符号长,CLOCK_PER_SEC转换为无符号长,然后返回该值。当它转换“滴答声”时,就会溢出。

相反,我希望它首先以“ ticks” / CLOCK_PER_SEC的两倍来计算值,然后将其转换为无符号长数。

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

您能解释一下为什么编译器会转换为无符号长整型“先验”吗,为什么即使使用无符号长整型也会以相同的值溢出? 有什么办法可以更好地编写Elapsed()函数,以防止溢出发生?

3 个答案:

答案 0 :(得分:4)

与普遍的看法相反,如果将double之类的浮点类型转换为 any 整型,则该行为为 undefined 。该整数类型。

因此在您的函数中引入double确实是一件很糟糕的事情。

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

答案 1 :(得分:3)

如果在您的系统上,clock_t是32位类型,则很可能会在2147秒后像您看到的那样回绕。这是预期的行为(参考clock)。而且没有足够的方法来解决这个问题。您的代码需要能够处理环绕(通过忽略它或通过显式考虑它)。

答案 2 :(得分:3)

  

当它转换“滴答声”时会溢出。

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

  

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

如果可以使用的话,一种替代方法是依靠POSIX标准而不是C标准库。它提供了clock_gettime,可用于获取timespec中表示的CPU时间。它不仅不会受到这种溢出(直到更长的时间跨度)的困扰,而且还可能具有比clock高的分辨率。 clock()的链接参考页也方便地显示了clock_gettime的示例用法。