It looks like there is no generic solution which supports integers of all possible sizes.
For a hardcoded list of types, I was able to make it work using __builtin_choose_expr
in C and overloaded function in C++. Here is the solution: https://github.com/pts/to-unsigned/blob/master/to_unsigned.h
The relevant C code looks like this:
#define TO_UNSIGNED(x) ( \
__builtin_choose_expr(__builtin_types_compatible_p(__typeof(x), unsigned char), (unsigned char)(x), \
__builtin_choose_expr(__builtin_types_compatible_p(__typeof(x), char), (unsigned char)(x), \
__builtin_choose_expr(sizeof(x) == sizeof(char), (unsigned char)(x), \
__builtin_choose_expr(__builtin_types_compatible_p(__typeof(x), unsigned short), (unsigned short)(x), \
__builtin_choose_expr(__builtin_types_compatible_p(__typeof(x), short), (unsigned short)(x), \
__builtin_choose_expr(sizeof(x) == sizeof(short), (unsigned short)(x), \
__builtin_choose_expr(__builtin_types_compatible_p(__typeof(x), unsigned), (unsigned)(x), \
__builtin_choose_expr(__builtin_types_compatible_p(__typeof(x), int), (unsigned)(x), \
__builtin_choose_expr(sizeof(x) == sizeof(int), (unsigned)(x), \
__builtin_choose_expr(__builtin_types_compatible_p(__typeof(x), unsigned long), (unsigned long)(x), \
__builtin_choose_expr(__builtin_types_compatible_p(__typeof(x), long), (unsigned long)(x), \
__builtin_choose_expr(sizeof(x) == sizeof(long), (unsigned long)(x), \
__extension__ __builtin_choose_expr(__builtin_types_compatible_p(__typeof(x), unsigned long long), (unsigned long long)(x), \
__extension__ __builtin_choose_expr(__builtin_types_compatible_p(__typeof(x), long long), (unsigned long long)(x), \
__extension__ __builtin_choose_expr(sizeof(x) == sizeof(long long), (unsigned long)(x), \
(void)0))))))))))))))))
Instead of __builtin_choose_expr
+ __builtin_types_compatible_p
, the equivalent _Generic
construct can also be used with compilers that support it, starting from C11.
C++11 has std::make_unsigned, and its implementation in libstdc++ explicitly enumerates the integer types it knows about, similar to how my C++ implementation of TO_UNSIGNED
does.