danpla
danpla

Reputation: 665

-Wtype-limits on attempt to limit an unsigned integer

Consider the following example:

unsigned short c = // ...
if (c > 0xfffful)
    c = 0xfffful;

Since unsigned short can actually be larger than 16 bits, I want to limit the value before snprintf it in hex format to a fixed-size buffer.

However, GCC (but not clang) gives a warning: comparison is always false due to limited range of data type [-Wtype-limits].

Is it a bug in GCC or I missed something? I understand that on my machine unsigned short is exactly 16 bits, but it's not guaranteed to be so on other platforms.

Upvotes: 10

Views: 603

Answers (2)

chessofnerd
chessofnerd

Reputation: 1279

I'd say it is not a bug. GCC is claiming if (c > 0xfffful) will always be false, which, on your machine, is true. GCC was smart enough to catch this, clang wasn't. Good job GCC!

On the other hand, GCC was not smart enough to notice that while it was always false on your machine, its not necessarily always false on someone else's machine. Come on GCC!

Note that in C++11, the *_least##_t types appear (I reserve the right to be proven wrong!) to be implemented by typedef. By the time GCC is running it's warning checks it likely has no clue that the original data type was uint_least16_t. If that is the case, the compiler would have no way of inferring that the comparison might be true on other systems. Changing GCC to remember what the original data type was might be extremely difficult. I'm not defending GCC's naive warning but suggesting why it might be hard to fix.

I'd be curious to see what the GCC guys say about this. Have you considered filing an issue with them?

Upvotes: 3

Lightness Races in Orbit
Lightness Races in Orbit

Reputation: 385264

This doesn't seem like a bug (maybe it could be deemed a slightly naive feature), but I can see why you'd want this code there for portability.

In the absence of any standard macros to tell you what the size of the type is on your platform (and there aren't any), I would probably have a step in my build process that works that out and passes it to your program as a -D definition.

e.g. in Make:

if ...
   CFLAGS += -DTRUNCATE_UINT16_LEAST_T
endif

then:

#ifdef TRUNCATE_UINT16_LEAST_T
    if (c > 0xfffful)
        c = 0xfffful;
#endif

with the Makefile conditional predicated on output from a step in configure, or the execution of some other C++ program that simply prints out sizeofs. Sadly that rules out cross-compiling.

Longer-term I propose suggesting more intelligent behaviour to the GCC guys, for when these particular type aliases are in use.

Upvotes: 0

Related Questions