为什么在代码中发生溢出(-2147483648)?

时间:2015-07-26 21:48:01

标签: c++ c++11 timestamp integer-overflow chrono

我看到非常奇怪的问题。以某种方式使用我的下面的代码,我看到负数被打印出来,如下面的holder变量所示。我不确定为什么会这样。

-2147483648 days -2147483648 hours -2147483648 minutes ago

这是我的时间戳(current_unix_timestamp)值1437943320,它将传递给我的下方法,之后holder值将会显示为上面所示为负数。

char holder[100];
get_timestamp_value(current_unix_timestamp, holder);

inline void get_timestamp_value(long sec_since_epoch_time, char* holder) {
    uint64_t timestamp = current_timestamp();
    double delta = timestamp/1000000 - sec_since_epoch_time;
    int days = floor(delta/60/60/24);
    int hours = floor((delta - days * 60 * 60 * 24)/60/60);
    int minutes = floor((delta - days * 60 * 60 * 24 - hours * 60 * 60)/60);
    holder[0] = 0;
    if (days) sprintf(holder, "%d days ", days);
    if (hours) sprintf(holder, "%s%d hours ", holder, hours);
    sprintf(holder, "%s%d minutes ago", holder, minutes);
    std::cout<< "Timestamp: " << timestamp << ", sec_since_epoch_time: " << sec_since_epoch_time << ", Delta:" << delta << ", Days: " << days << ", hours: " << hours << ", mins: " << mins << std::endl;
}

// get current system time in microseconds since epoch
inline uint64_t current_timestamp()
{
    std::chrono::time_point<std::chrono::steady_clock> ts = std::chrono::steady_clock::now();
    return std::chrono::duration_cast<std::chrono::microseconds>(ts.time_since_epoch()).count();
}

现在这是从上面cout日志中打印出来的内容:

Timestamp: 433430278724, sec_since_epoch_time: 1437943320, Delta:1.84467e+19, Days: -2147483648, hours: -2147483648, mins: -2147483648
Timestamp: 433679536303, sec_since_epoch_time: 1437943380, Delta:1.84467e+19, Days: -2147483648, hours: -2147483648, mins: -2147483648
Timestamp: 433929683258, sec_since_epoch_time: 1437943440, Delta:1.84467e+19, Days: -2147483648, hours: -2147483648, mins: -2147483648
Timestamp: 434179628271, sec_since_epoch_time: 1437943500, Delta:1.84467e+19, Days: -2147483648, hours: -2147483648, mins: -2147483648

上述代码中是否发生了导致此问题的错误?任何建议都会有很大的帮助。

1 个答案:

答案 0 :(得分:1)

您应该尽量避免使用有符号和无符号整数类型的混合进行算术运算。结果往往令人惊讶。

显然,timestamp不是您期望的值,因为timestamp/1000000是433430,远远小于sec_since_epoch_time。因此,您可能希望timestamp/1000000 - sec_since_epoch_time为负数,但(令人惊讶的是,如上所述),它将是一个大的正数,因为签名的长sec_since_epoch_time先前已转换为unsigned long减法,遵循通常的算术转换规则。然后使用无符号算术完成减法,因此结果是一个略小于2 64 的正数,如delta的值所示。

将该大数除以86400不足以使其达到int的范围,因此分配

int days = floor(delta/60/60/24);

会溢出未定义的后果(在这种情况下,将days设置为-2 31 。)

对我来说,要求持续时间以微秒为单位然后将它除以一百万,这似乎有点奇怪。为什么不在几秒钟内询问持续时间?

但潜在的问题是,您要将current_timestamp返回的值(即std::chrono::steady_clock纪元以来的微秒数)与参数sec_since_epoch_time进行比较。在我看来,sec_since_epoch_time是自Unix时代(1970年1月1日)以来的秒数。但是,无法保证std::chrono时钟的纪元具有该值。 (显然,在Linux上,std::chrono:system_clock的时代是系统时代,但我重复一遍,不能保证。)

你不能比较自纪元以来的两个&#34;秒#34;值,除非它们是同一时期以来的秒数。这意味着代码可以工作的唯一方式是,最初用于获取sec_since_epoch_time值的时钟与您在current_timestamp中使用的时钟相同。

除了确保timestamp实际具有预期值之外,您还应将timestamp更改为int64_t(或将其转换为int64_t以进行计算delta)。