我正在使用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()函数,以防止溢出发生?
答案 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
的示例用法。