Is there an elegant way to cast a bigger datatype to a smaller one without causing the result to overflow?
E.g. casting 260 to uint8_t should result in 255 instead of 4.
A possible solution would be:
#include <limits.h>
#include <stdint.h>
inline static uint8_t convert_I32ToU8(int32_t i32)
{
if(i32 < 0) return 0;
if(i32 > UINT8_MAX) return UINT8_MAX;
return (uint8_t)i32;
}
Although this solution works, I wonder if there is a better way (without having to create lots of conversion functions).
Solution should be in C (with optionally GCC compiler extensions).
Since C11 you can use the new
_Genericselection featureYou can remove the unnecessary types to make it shorter. After that just call it as
CLAMP(type, value)like thisThis way you can clamp to almost any types, including floating-point types or
_Boolif you add more types to the support list. Beware of the type width and signness issues when using itDemo on Godlbolt
You can also use the GNU
typeofor__auto_typeextensions to make theCLAMPmacro cleaner and safer. These extensions also work in older C versions so you can use them in you don't have access to C11Another simple way to do this in older C versions is to specify the destination bitwidth
Beside the fact that it doesn't work for
long longandunsigned long longwithout some changes, this also implies the use of 2's complements. You can callCLAMPwith a negative bit width to indicate a signed type or callCLAMP_SIGN/CLAMP_UNSIGNdirectionAnother disadvantage is that it just clamps the values and doesn't cast to the expected type (but you can use
typeofor__auto_typeas above to return the correct type)Demo on Godbolt