Reputation: 305
I have the following check where it is possible for the condition to underflow.
uint16_t lo;
uint16_t input;
...
uint16_t newLo = std::clamp(lo-input, 0, lo);
This causes a compiler error due to the promotion of types to int when doing the calculation ("Compiler error" is caused by gcc flags: -Wall -Werror
).
Is it safe to statically cast the value of the calculation if it can cause an underflow?
uint16_t lo;
uint16_t input;
...
uint16_t compVal = static_cast<uint16_t>(lo-input);
uint16_t newLo = std::clamp(compVal, 0, lo);
Upvotes: 0
Views: 1443
Reputation: 3018
Assuming you really need the type uint16_t
and you really want to use std::clamp
:
// int can hold any uint16_t
uint16_t newLo = std::clamp(static_cast<int>(lo) - static_cast<int>(input),
0,
static_cast<int>(lo));
You could also simply do this:
uint16_t newLo = input < lo ? lo - input : 0;
The above is assuming that the behaviour you expect (which is not entirely clear from the question) is the same as if your uint16_t
were a int
, that is: 3 - 5 returns 0.
As an additional note, I would avoid subtracting a value from an uint
whenever possible.
Upvotes: 0
Reputation: 37657
Since you are using std::clamp
with argument 0
as second argument then apparently you are expecting possible negative value.
uint16_t compVal = static_cast<uint16_t>(lo-input);
uint16_t newLo = std::clamp(compVal, {}, lo);
This fixes compile error, but hides actual problem when lo < input
.
Actual behavior will wrap around actual value and compVal
will always be greater or equal zero. I do not think this is what you are expecting.
The most resolvable approach was proposed by @Ayxan in a comment:
uint16_t newLo = std::clamp(lo - input, 0, +lo);
Here all arguments of clamp
are int
type, then result is silently converted to uint16_t
and you have a guarantee that there is no integer overflow since result will fit into destination type.
Upvotes: 2