Home > front end >  Disable type-limits check for a macro
Disable type-limits check for a macro

Time:02-25

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?

CodePudding user response:

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)

CodePudding user response:

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))

CodePudding user response:

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).

CodePudding user response:

Time for a hideous workaround:

#define SIGNOF_(a) ((a) < 0 ? -1 : 1)

#ifdef __GNUC__
#define SIGNOF(a)   ({ \
        typeof(a) _a = (a); \
        _Pragma("GCC diagnostic push") \
        _Pragma("GCC diagnostic ignored \"-Wtype-limits\"") \
        int _r = SIGNOF_(_a); \
        _Pragma("GCC diagnostic pop") \
        _r; })
#else
#define SIGNOF(a)   SIGNOF_(a)
#endif

It makes use of GNU C "statement expressions" (({ statements; })) and the typeof operator. The initialization _a = (a); is to catch any -Wtype-limit warnings in the macro parameter a before the warning is temporarily disabled by the pragmas.

  •  Tags:  
  • c
  • Related