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).
CodePudding user response:
IMO best way to do it is first map constant describing limits into constant with desiried case. Then define macro which will use this new constant.
So basic idea looks like this:
const int8_t min_of_int8 = INT8_MIN;
const int8_t max_of_int8 = INT8_MAX;
const uint8_t min_of_uint8 = 0;
const uint8_t max_of_uint8 = UINT8_MAX;
....
#define DEFINE_CONVERTER(SRC, DST) \
inline static DST ## _t convert_ ## SRC ## _to_ ## DST (SRC ## _t src) \
{ \
return src < min_of_ ## DST ? min_of_ ## DST : (src > max_of_ ## DST ? max_of_ ## DST : (DST ## _t)src); \
}
DEFINE_CONVERTER(int32, uint8)
DEFINE_CONVERTER(int32, int8)
....
Here is test written using C .
Test it carefully since some implicit conversion may lurking and breaking this macro for specific pair of types.
If you wish to have different pattern for function names (like this I8
U32
) then do same trick as for constant and define respective typedef
which name will contain desired short versions of types.
Note similar approach is used on OpenSSL to provide same functions for different types.