C comparison 'x < 0' where type of 'x' is arbitrary, i.e. might be unsigned

107 Views Asked by At

GIVEN:

A type defined as TheValueT that may be arbitrarily configured, e.g. as uint8_t or int64_. Let there be some code:

TheValueT   x = ...;

... do something to 'x' ...

if( x < 0 ) {
   /* Do something. */
}

PROBLEM:

It happens that if TheValueT is defined as an unsigned type, the compiler complains about 'condition always true because of limited range of type ...'.

QUESTION:

How can the compiler warning be avoided whilst letting TheValueT still be of arbitrary integer type? The solution should be applicable to the widest range of C compilers.

3

There are 3 best solutions below

4
John Bollinger On BEST ANSWER

A simple and safe way to write your test would be this:

TheValueT x = /* ... */;

if (x < 1 && x != 0) {
    // do something
}

It is possible that a clever enough compiler would warn about that anyway, but the same is true of any correct alternative that can be written to cover all possible integer types (including extension types). That does work around the warning in my implementation.

No alternative requiring an arithmetic computation involving the value of x definedly produces the correct result in all cases -- these run into problems with values of x at the extremes of its or other types' ranges.

This does assume that TheTypeT must be an integer type. If floating types are a possibility, too, then your best bet may be to just live with the warning, or to use a compiler flag to turn off that particular warning during production builds.

3
chux - Reinstate Monica On

Perhaps a Generic solution?

#include <stdio.h>
#include <stdlib.h>

#define less_than_zero(x) _Generic((x) + 0, \
  int: (x) < 0, \
  long: (x) < 0, \
  long long: (x) < 0, \
  default: (x) * 0 \
  )

#if 1
int main(void) {
  short sh = -1;
  int i = -1;
  long long ll = -1;
  unsigned short us = -1u;
  unsigned u = -1u;
  unsigned long long ull = -1u;

  if (less_than_zero(sh)) puts("sh");
  if (less_than_zero(i)) puts("i");
  if (less_than_zero(ll)) puts("ll");
  if (less_than_zero(us)) puts("us");
  if (less_than_zero(u)) puts("u");
  if (less_than_zero(ull)) puts("ull");
  return 0;
}

No condition always true because of limited range of type warning.
Output

sh
i
ll
1
chux - Reinstate Monica On

Variation on a theme. Works for FP too.

if (x <= 0 && x != 0) {