Buoy
Buoy

Reputation: 305

Static cast from negative int to uint

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

Answers (2)

mfnx
mfnx

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

Marek R
Marek R

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.

Demo

Upvotes: 2

Related Questions