How to test `int` to `size_t` conversion without warning "comparison is always true"?

StackOverflow https://stackoverflow.com/questions/22235658

  •  10-06-2023
  •  | 
  •  

Question

How to re-write code to implement the same test, but portably avoid the warning?


AFAIK, INT_MAX and SIZE_MAX are not defined to one always being >= than the other, hence the use for the following function to detect problems converting from int to size_t.

#include <assert.h>
#include <stddef.h>
#include <stdint.h>

size_t int_to_size_t(int size) {
  assert(size >= 0);

  #pragma GCC diagnostic ignored "-Wtype-limits"

  // Without the above pragma, below line of code may cause:
  // "warning: comparison is always true due to limited range of data type
  // [-Wtype-limits]"
  assert((unsigned)size <= SIZE_MAX);

  #pragma GCC diagnostic warning "-Wtype-limits"

  return (size_t) size;
}

Different compilers use various mechanisms to squelch warnings. I looking for a portable solution.

The above soluton is not portable and this gcc method unfortunately has a side-effect: Warning -Wtype-limits, which may or may not have been enabled is now enabled after this code. Do not know how to restore -Wtype-limits setting.

Ref:
Portability of #warning preprocessor directive
Suppress comparison always true warning for Macros?

Was it helpful?

Solution

You could replace this:

assert((unsigned)size <= SIZE_MAX);

by:

#if INT_MAX > SIZE_MAX
assert((unsigned)size <= SIZE_MAX);
#endif

If the #if condition is false, the assert condition is always true and the assert is unnecessary. The (unsigned) cast is (probably) necessary to avoid a warning about a comparison between signed and unsigned operands.

Warning: I have not tested this. (To fully test it, I'd need access to a system with int wider than size_t, and I've never seen such a system.)

OTHER TIPS

As Keith states correctly, you'd only have to worry when the value of INT_MAX is greater than the one for SIZE_MAX. If you want to compare these values in the preprocessor (and you should) you can't cast to make INT_MAX an unsigned type. (The preprocessor doesn't know about casts.)

Therefore you have to add 0U to the value so both expression become uintmax_t. (For the preprocessor integer constants are intmax_t or uintmax_t).

#if (INT_MAX+0U) > SIZE_MAX
assert(size <= (int)SIZE_MAX);
#endif

Then inside this #if you know that SIZE_MAX is less that INT_MAX so you may cast it down to int without changing the value.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top