warning: comparison is always true due to limited range of data type

G

Guest

I have the following expression coded in a macro:

((((__typeof__((x)))0) - ((__typeof__((x)))1)) < ((__typeof__((x)))0))

It uses GCC's extension __typeof__() but I don't think that's an issue.
This expression is intended to evaluate true whenever x is a signed integer
and false whenever x is an unsigned integer. The purpose is to give the
compiler a good chance at optimizing out the expressions that follow in the
?: trinary operator. Since this expression is strictly a constant, it should
be easy to detect that only one or the other of the ?: expressions is needed.

When I use int, long, or long long, either signed or unsigned, this compiles
without any warning. When I use signed short, it is also without warning.
But when I use unsigned short, I get the warning.

Clearly, the result will be out of range for unsigned, although it will be
converted back into range. What puzzles me more than getting it for unsigned
short is NOT getting it for unsigned int. That doesn't seem consistent. Is
there something special in the standard that would make such an expression,
or the conversion involved in that arithmetic, be different for int compared
to short?

Here's the expression with hard coded types for easier reading (although for
no practical purpose):

((signed short)0) - ((signed short)1) < ((signed short)0)
((unsigned short)0) - ((unsigned short)1) < ((unsigned short)0)

((signed int)0) - ((signed int)1) < ((signed int)0)
((unsigned int)0) - ((unsigned int)1) < ((unsigned int)0)
 
B

Ben Pfaff

((unsigned short)0) - ((unsigned short)1) < ((unsigned short)0)

I don't think that this does what you want. Due to the way that
arithmetic promotions work, I think that it ordinarily evaluates
to -1 < 0, which evaluates to 1.

Indeed, on my system:

blp@blp:~(0)$ cat > tmp.c
#include <stdio.h>
int
main(void)
{
printf("%d\n",((unsigned short)0) - ((unsigned short)1) < ((unsigned short)0));
return 0;
}
blp@blp:~(0)$ gcc tmp.c
blp@blp:~(0)$ ./a.out
1
blp@blp:~(0)$
 
K

Keith Thompson

Ben Pfaff said:
I don't think that this does what you want. Due to the way that
arithmetic promotions work, I think that it ordinarily evaluates
to -1 < 0, which evaluates to 1.

Indeed, on my system:

blp@blp:~(0)$ cat > tmp.c
#include <stdio.h>
int
main(void)
{
printf("%d\n",((unsigned short)0) - ((unsigned short)1) < ((unsigned short)0));
return 0;
}
blp@blp:~(0)$ gcc tmp.c
blp@blp:~(0)$ ./a.out
1
blp@blp:~(0)$

Here's something that does what you probably want:

#include <stdio.h>
int main(void)
{
if ((unsigned short)-1 < (unsigned short)0) {
puts("unsigned short is a signed type (?!?!?!)");
}
else {
puts("unsigned short is an unsigned type");
}
return 0;
}
 
E

Eric Sosman

Keith said:
#include <stdio.h>
int main(void)
{
if ((unsigned short)-1 < (unsigned short)0) {
puts("unsigned short is a signed type (?!?!?!)");
}
else {
puts("unsigned short is an unsigned type");
}
return 0;

Is the second cast necessary? (Have I missed something,
yet again?)
 
S

Stefan Ram

Eric Sosman said:
Is the second cast necessary? (Have I missed something,
yet again?)

Without the second cast, the first operand will be
converted (promoted) to »int«, but since it already
has a positive value, the result should be the same.
 
G

Guest

| (e-mail address removed) writes:
|
|> ((unsigned short)0) - ((unsigned short)1) < ((unsigned short)0)
|
| I don't think that this does what you want. Due to the way that
| arithmetic promotions work, I think that it ordinarily evaluates
| to -1 < 0, which evaluates to 1.
|
| Indeed, on my system:
|
| blp@blp:~(0)$ cat > tmp.c
| #include <stdio.h>
| int
| main(void)
| {
| printf("%d\n",((unsigned short)0) - ((unsigned short)1) < ((unsigned short)0));
| return 0;
| }
| blp@blp:~(0)$ gcc tmp.c
| blp@blp:~(0)$ ./a.out
| 1
| blp@blp:~(0)$

Oh ... I got caught by that one. The promotion to int happens BEFORE the
minus operation. Ouch.

OK, silly code removed (it was only an optimization hint, anyway).
 
P

Peter Nilsson

  Without the second cast, the first operand will be
  converted (promoted) to »int«, but since it already
  has a positive value, the result should be the same.

If unsigned short promotes to int, then both sides of <
will be promoted to int. [If you accept that int 'promotes'
to int.] If unsigned short promotes to unsigned int, then
both sides will promote to unsigned int. Both cases are
irrespective of the second cast since int will promote
(via usual arithmetic conversions) to usigned int if the
left operand promotes to unsigned int.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,994
Messages
2,570,223
Members
46,812
Latest member
GracielaWa

Latest Threads

Top