隐式转换双重到无符号长溢出 c++

Implicit conversion double to unsigned long overflow c++

本文关键字:无符号 溢出 c++ 转换      更新时间:2023-10-16

我正在使用 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(( 返回计算值时,我正在执行从双精度到无符号长整型的隐式转换。 32 位系统的无符号长限制为 2,147,483,647,在 Elapsed(( 返回 2146 后我溢出。

看起来该函数将"ticks"转换为无符号长整型,CLOCK_PER_SEC转换为无符号长整型,然后返回值。当它转换"即时报价"时,它会溢出。

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

在尝试计算更多秒数时,我尝试返回一个无符号的长长数据类型,但变量总是以相同的值 (2147( 溢出。

你能解释一下为什么编译器会转换为无符号长长"先验",为什么即使有无符号长长,它也会以相同的值溢出? 有没有办法以更好的方式编写 Elapsed(( 函数来防止溢出发生?

与普遍的看法相反,如果值无法适应浮点类型(如double(到任何整型类型,则未定义将浮点类型转换为整型类型的行为。

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

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

如果您的系统上,clock_t是 32 位类型,那么它很可能会像您看到的那样在 2147 秒后环绕。这是预期行为(参考。clock(。再多的选角也无法绕过这一点。您的代码需要能够处理环绕(通过忽略它或显式说明它(。

当它转换"ticks"时,它会溢出。

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

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

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