paul_schaefer
paul_schaefer

Reputation: 431

How to tell compiler the "range" of a #define (-Wtype-limits warning)

In my code, I need to saturate a variable uint32_t var within a range [MIN, MAX]. MIN and MAX are defined as macros, so I can change these values easily inside a header file.

Header:

#define MIN    (0)
#define MAX    (1000)

Code:

if(var > MAX){
    var = MAX;
}else if(var < MIN){
    var = MIN;
}

When I now use compiler flag -Wtype-limits, I get a warning that the second check var < MIN is always false. This warning suggests that I can remove the second comparison.

This makes sense as long as I define #define MIN (0) but, when changing this to let's say #define MIN (10), then the second comparison is mandatory.

So my question: How can I tell the compiler, that MIN can be any value greater or equal zero?

Upvotes: 5

Views: 449

Answers (3)

stark
stark

Reputation: 13189

This solves the issue:

int main(void) {
    unsigned int var = rand();

    if (var > MAX){
        var = MAX;
    }
#if MIN > 0
    else if (var < MIN) {
        var = MIN;
    }
#endif

    printf("token = %u\n", var);
}

Edit: reduce "dirtiness" by making it clear what the two cases are.

uint32_t saturate(uint32_t var)
{
#if MIN > 0
    if (var > MAX){
        var = MAX;
    }
    else if (var < MIN) {
        var = MIN;
    }
#else
    // Only need to do the upper bound
    if (var > MAX){
        var = MAX;
    }
#endif
    return var;
}

Upvotes: 3

Lundin
Lundin

Reputation: 214265

How can I tell the Compiler, that MIN can be any value greater or equal zero?

You can't, you just told it that it is exactly zero.

This warning comes from the compiler's ability to evaluate integer constant expressions at compile time, so it sees var < 0 and spots that var is an unsigned type.

We can prevent that and get rid of the warning by using a variable instead, so it's no longer an integer constant expression:

const unsigned int MIN = 0;

Or alternatively, if you must have a macro for some reason, use a compound literal:

#define MIN    (const unsigned int){0}

Now of course don't write weird stuff like that without comments, so the correct production code would be for example:

// MIN is using compound literal to block unsigned vs 0 comparison warnings in gcc 1.2.3
#define MIN (const unsigned int){0} 

Upvotes: 0

phuclv
phuclv

Reputation: 41914

The simplest solution is just use <= instead of <

if (var >= MAX) {
    var = MAX;
} else if (var <= MIN) {
    var = MIN;
}

But you should avoid macros if possible and just declare constants instead. Besides always use the U suffix when you work with unsigned values to avoid signed-unsigned incompatibility warnings. In fact it's quite interesting to see that if I use #define like that I get a warning in GCC but not Clang, and when I change to const and add the U suffix then I get no warning with GCC but one with Clang

Upvotes: 5

Related Questions