Почему переполнение (-2147483648) происходит в коде?
Я вижу довольно странную проблему. Каким-то образом, с моим кодом ниже, я вижу, как выводится отрицательное число, как показано ниже в моем 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 ответ
Вам следует избегать арифметических операций со смесью целых типов со знаком и без знака. Результаты часто бывают удивительными.
Очевидно, что timestamp
это не то значение, которое вы ожидаете, так как timestamp/1000000
433430, что значительно меньше sec_since_epoch_time
, Следовательно, вы можете ожидать timestamp/1000000 - sec_since_epoch_time
быть отрицательным числом, но (как ни удивительно, как указано выше), это будет большое положительное число, потому что подписанный длинный sec_since_epoch_time
превращается в unsigned long
до вычитания, следуя правилам для обычных арифметических преобразований. Вычитание затем выполняется с использованием арифметики без знака, так что результатом является положительное число, немного меньшее 264, как видно из значения delta
,
Деления этого большого числа на 86400 недостаточно, чтобы привести его в диапазон int
, так что назначение
int days = floor(delta/60/60/24);
будет переполнен с неопределенными последствиями (в этом случае настройка days
до -231.)
Мне кажется немного странным спрашивать длительность в микросекундах, а затем делить ее на миллион. Почему бы просто не спросить продолжительность в секундах?
Но основная проблема заключается в том, что вы сравниваете значение, возвращаемое current_timestamp
, который является числом микросекунд с эпохи std::chrono::steady_clock
с аргументом sec_since_epoch_time
, Это выглядит как sec_since_epoch_time
количество секунд с начала эпохи Unix (1 января 1970 г.). Тем не менее, нет никаких гарантий, что эпоха для std::chrono
часы имеют это значение. (Видимо, в Linux эпоха для std::chrono:system_clock
это системная эпоха, но повторюсь, гарантии нет.)
Вы не можете сравнивать две "секунды с начала эпохи", если они не являются секундами с той же эпохи. Это означает, что ваш код может работать только в том случае, если часы, которые изначально использовались для получения значения sec_since_epoch_time
такие же часы, как вы используете в current_timestamp
,
В дополнение к обеспечению того, что timestamp
на самом деле имеет ожидаемое значение, вы должны изменить timestamp
для int64_t
(или приведите его к int64_t
для целей расчета delta
).