C unsigned comparison

Discussion of chess software programming and technical issues.

Moderator: Ras

User avatar
hgm
Posts: 28464
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

C unsigned comparison

Post by hgm »

If I have

Code: Select all

unsigned int u;

u = -1;
if(u == -1) ...;
what would it mean?

My understanding has always been that expressions that mix int and unsigned int would convert all operands to unsigned int, before applying the operator. So that the code would be equivalent to

Code: Select all

unsigned int u;

u = (unsigned int) -1;
if(u == (unsigned int) -1) ...;
On 2-complement architectures (are there still any other) a cast from signed to unsigned integer data types of the same length would be a no-op, and preserve the bit pattern 0xFFFFFFFF.

Clang, however, issues a warning that the comparison will never yield true,..
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: C unsigned comparison

Post by bob »

hgm wrote:If I have

Code: Select all

unsigned int u;

u = -1;
if(u == -1) ...;
what would it mean?

My understanding has always been that expressions that mix int and unsigned int would convert all operands to unsigned int, before applying the operator. So that the code would be equivalent to

Code: Select all

unsigned int u;

u = (unsigned int) -1;
if(u == (unsigned int) -1) ...;
On 2-complement architectures (are there still any other) a cast from signed to unsigned integer data types of the same length would be a no-op, and preserve the bit pattern 0xFFFFFFFF.

Clang, however, issues a warning that the comparison will never yield true,..
My "favorite" compiler.

I just tried it and got no warning at all.

this is version 7.0.2

When I ran your code it seemed to work just fine. clang never did know its a$$ from its elbow...
Rein Halbersma
Posts: 752
Joined: Tue May 22, 2007 11:13 am

Re: C unsigned comparison

Post by Rein Halbersma »

hgm wrote:If I have

Code: Select all

unsigned int u;

u = -1;
if(u == -1) ...;
what would it mean?

My understanding has always been that expressions that mix int and unsigned int would convert all operands to unsigned int, before applying the operator. So that the code would be equivalent to

Code: Select all

unsigned int u;

u = (unsigned int) -1;
if(u == (unsigned int) -1) ...;
On 2-complement architectures (are there still any other) a cast from signed to unsigned integer data types of the same length would be a no-op, and preserve the bit pattern 0xFFFFFFFF.

Clang, however, issues a warning that the comparison will never yield true,..
Can you show a reproducible online example? Here's an online clang 3.7.0 code example that only gives an innocent warning.
http://coliru.stacked-crooked.com/a/a82f0370656f9809
AlvaroBegue
Posts: 932
Joined: Tue Mar 09, 2010 3:46 pm
Location: New York
Full name: Álvaro Begué (RuyDos)

Re: C unsigned comparison

Post by AlvaroBegue »

I agree that the compiler's behavior you describe (which I cannot reproduce either) seems wrong.

If you want to be completely in the clear, I think this is the way to go:

Code: Select all

#include <stdio.h>
 
int main()  {
  unsigned int u;
  u = ~0u;
  if (u == ~0u) 
    puts("OK");
}
abulmo
Posts: 151
Joined: Thu Nov 12, 2009 6:31 pm

Re: C unsigned comparison

Post by abulmo »

hgm wrote:If I have

Code: Select all

unsigned int u;

u = -1;
if(u == -1) ...;
what would it mean?

My understanding has always been that expressions that mix int and unsigned int would convert all operands to unsigned int, before applying the operator. So that the code would be equivalent to

Code: Select all

unsigned int u;

u = (unsigned int) -1;
if(u == (unsigned int) -1) ...;
On 2-complement architectures (are there still any other) a cast from signed to unsigned integer data types of the same length would be a no-op, and preserve the bit pattern 0xFFFFFFFF.
-1 is always converted to the biggest unsigned integer value, whatever the architecture, because of the arithmetic of unsigned integers.
Clang, however, issues a warning that the comparison will never yield true,..
clang (3.7) only issues this kind of warning if the signed type is of higher rank than the unsigned type. For example:

Code: Select all

unsigned short u = -1;
    if (u == -1) { /*...*/

warning: comparison of constant -1 with expression of type 'unsigned short' is always false [-Wtautological-constant-out-of-range-compare]

Otherwise it just complains about a comparison between an integer or an unsigned integer. This latter warning is just here to tell the coder he may do something wrong.
Richard
Rein Halbersma
Posts: 752
Joined: Tue May 22, 2007 11:13 am

Re: C unsigned comparison

Post by Rein Halbersma »

AlvaroBegue wrote:I agree that the compiler's behavior you describe (which I cannot reproduce either) seems wrong.

If you want to be completely in the clear, I think this is the way to go:

Code: Select all

#include <stdio.h>
 
int main()  {
  unsigned int u;
  u = ~0u;
  if (u == ~0u) 
    puts("OK");
}
on two's complement implementations, there is no real danger with the original code: unsigned int and signed int have the same rank and the latter will be value-converted to the former.
mar
Posts: 2675
Joined: Fri Nov 26, 2010 2:00 pm
Location: Czech Republic
Full name: Martin Sedlak

Re: C unsigned comparison

Post by mar »

hgm wrote:If I have

Code: Select all

unsigned int u;

u = -1;
if(u == -1) ...;
what would it mean?

My understanding has always been that expressions that mix int and unsigned int would convert all operands to unsigned int, before applying the operator. So that the code would be equivalent to

Code: Select all

unsigned int u;

u = (unsigned int) -1;
if(u == (unsigned int) -1) ...;
On 2-complement architectures (are there still any other) a cast from signed to unsigned integer data types of the same length would be a no-op, and preserve the bit pattern 0xFFFFFFFF.

Clang, however, issues a warning that the comparison will never yield true,..
That's strange becase conversions from signed to unsigned integers are well defined by the standard, -1 converts to max uint, no matter if it uses 2's complement or not.
If the compiler claims the comparison never yields true then it's simply broken.
Rein Halbersma
Posts: 752
Joined: Tue May 22, 2007 11:13 am

Re: C unsigned comparison

Post by Rein Halbersma »

abulmo wrote:
Clang, however, issues a warning that the comparison will never yield true,..
clang (3.7) only issues this kind of warning if the signed type is of higher rank than the unsigned type. For example:

Code: Select all

unsigned short u = -1;
    if (u == -1) { /*...*/

warning: comparison of constant -1 with expression of type 'unsigned short' is always false [-Wtautological-constant-out-of-range-compare]

Otherwise it just complains about a comparison between an integer or an unsigned integer. This latter warning is just here to tell the coder he may do something wrong.
Yes, you nailed the root cause. FWIW, gcc also warns about it
http://coliru.stacked-crooked.com/a/f22a26eba4e91192
AlvaroBegue
Posts: 932
Joined: Tue Mar 09, 2010 3:46 pm
Location: New York
Full name: Álvaro Begué (RuyDos)

Re: C unsigned comparison

Post by AlvaroBegue »

Rein Halbersma wrote:
AlvaroBegue wrote:I agree that the compiler's behavior you describe (which I cannot reproduce either) seems wrong.

If you want to be completely in the clear, I think this is the way to go:

Code: Select all

#include <stdio.h>
 
int main()  {
  unsigned int u;
  u = ~0u;
  if (u == ~0u) 
    puts("OK");
}
on two's complement implementations, there is no real danger with the original code: unsigned int and signed int have the same rank and the latter will be value-converted to the former.
It's not so much a matter of "danger", but of expressing intent as clearly as possible. If you want a pattern of all 1s, you can get it easily the way I proposed, and the resulting constant has the right type, so the compiler won't look at it funny.

I am not so sure that the standard guarantees that the -1 will work, anyway. Can you point to the specific paragraph?
User avatar
hgm
Posts: 28464
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: C unsigned comparison

Post by hgm »

I don't have Clang, but this issue is triggered by a bug report on XBoard, where someone tries to compile it for Mac with Clang. The build log contains the following warning:

Code: Select all

moves.c:1337:26: warning: comparison of constant -4 with expression of type
      'ChessSquare' is always false
      [-Wtautological-constant-out-of-range-compare]
    if (board[EP_STATUS] == EP_IRON_LION && (board[rt][ft] == WhiteLion ...
        ~~~~~~~~~~~~~~~~ ^  ~~~~~~~~~~~~
Now based on what people remarked here there could be a genuine problem: board[] is declared as ChessSquare, which is an enum type. In the gcc that I am using this is apparently always implemented as (unsigned int). But the range of the enum does not extend beyond 256, so it could very well be that Clang implements it as (unsigned char). In that case there would be a problem, because board[EP_STATUS] = -4; would assign 0xFF to it, which would not be sign extended on conversion to (unsigned int).

I guess I will have to be more careful here, and cast the ChessSquare to (signed char) before doing the comparison.