What happened when constructing a variable of std::chrono::milliseconds from "LLONG_MAX seconds"?

Viewed 198

When constructing a variable of std::chrono::milliseconds from "LLONG_MAX seconds", the result t_milli.count() is -1000

auto t_max_seconds = std::chrono::seconds(LLONG_MAX);
auto t_milli = std::chrono::milliseconds(t_max_seconds);

As far as I can see, somehow "-1" came from "LLONG_MAX", and "1000" was the ratio.
(for "microseconds", the result is -1'000'000)

I wonder what happend here, an overflow or undefined-behavior?

2 Answers

You are getting signed overflow in the conversion from seconds to milliseconds.

On your machine both seconds and milliseconds are represented by signed 64 bit integers. But to convert seconds to milliseconds, the library multiplies by 1000.

You are effectively doing this:

cout << LLONG_MAX*1000 << '\n';

which on my machine prints out:

-1000

std::chrono::seconds is a std::chrono::duration<>, just like std::chrono::milliseconds. As you figured, std::chrono::milliseconds has a ratio of std::milli, which is std::ratio<1,1000>.

The Undefined Behavior here is that the representation of std::chrono::seconds may have as little as 35 bits. Only std::chrono::nanoseconds is required to have a (signed) 64 bit representation, and LLONG_MAX could even be higher than that.

Of course you can define using seconds = std::chrono::duration<std::int64_t>;. There's nothing magical about std::chrono::seconds. Converting that to milliseconds has its own overflow risk, naturally.

I suspect you want std::chrono::seconds::max().

Related