I'm trying to build a simple SIGNOF macro:
#define SIGNOF(a) ((a) < 0 ? -1 : 1)
If a is negative it should return -1, otherwise 1. If a is an unsigned type, it should always return 1 and the compiler can optimize away the negative code path.
However, GCC rightfully warns me that
error: comparison of unsigned expression in ‘< 0’ is always false [-Werror=type-limits]
29 | #define SIGNOF(a) ((a) < 0 ? -1 : 1)
But in this case I actually want this behavior. Is there any way to tell the compiler that this is intentional, similar to /* fall-though */ in a switch-case?
If your compiler supports it, you can use _Generic:
#define SIGNOF(a) _Generic(a, unsigned char: 1, \
unsigned short: 1, \
unsigned int: 1, \
unsigned long: 1, \
unsigned long long: 1, \
default: (a) < 0 ? -1 : 1)
What works is
static inline int __signof(long long a)
{
return a < 0 ? -1 : 1;
}
#define SIGNOF(a) _Generic(a, unsigned char: 1, \
unsigned short: 1, \
unsigned int: 1, \
unsigned long: 1, \
unsigned long long: 1, \
default: __signof(a))
This seems to fix the warning problem, at the expense of evaluating the operand twice:
#define SIGNOF(a) ((a) == 0 ? +1 : ((a) > 0) ? +1 : -1)
I observe that since the proposed DIV_ROUND() macro evaluates both its arguments twice, it also has problems if the arguments have side effects (increments, function calls, etc).