Re: Style question: comparison between signed and unsigned?

Gerard Roudier (groudier@club-internet.fr)
Fri, 26 Sep 1997 23:14:12 +0200 (MET DST)


On 25 Sep 1997, Kai Henningsen wrote:

> tytso@MIT.EDU (Theodore Y. Ts'o) wrote on 23.09.97 in <199709232326.TAA00806@dcl.MIT.EDU>:
>
> > From: Ulrich Drepper <drepper@ipd.info.uni-karlsruhe.de>
> > Date: 24 Sep 1997 00:03:11 +0200
> >
> > What I would like to see and which catches most cases I came across is
> > that gcc does not warn in this case:
> >
> > ssize_t n = read (...);
> > if (n < 0)
> > ...
> > else
> > {
> > if (n < sizeof (foo))
> > ...
> > }
> >
> > At least when optimizing gcc knows that when executing the second `if'
> > the variable `n' cannot be negative and since
> > sizeof(ssize_t)==sizeof(size_t) there is no reason for a warning.
> >
> > Actually, GCC can do better than that. 99.97% of the time, sizeof(foo)
> > is less than 2**31, so as long as you do a signed comparison, the right
> > thing will happen anyway. There's no need to any kind of flow analysis
> > to figure this out!
>
> Unfortunately, the C standard says that you MUST do an unsigned
> comparision (if the signed type isn't larger than the unsigned one, as in
> the above example).

Not only the C standard says the comparison must be unsigned, but it
says, if I remember correctly, that it will be so.

I say that a compiler shall warn only if it is not clever enough to deduce
from the above code that 'n' cannot be negative when compared to the
sizeof(foo), since:

if (n < 0) then ((unsigned)n < sizeof(foo)) is FALSE.
((unsigned)(NEGATIVE VALUE) >= 2**31) with bit to bit conversion.

There is 2 ways for adding a cast that will make the stupid compiler
happy:

1 - ( (unsigned) n < sizeof(foo) )
2 - ( n < (signed) sizeof(foo) )

(1) is very stupid and broken in my opinion since it will not fix the
problem but just hide it. However I bet you that lots of programmers will
use (1) just for doing as the stupid compiler will do.

Here are some messes we have to deal with, due to ANSI C:

- sizeof() is size_t type, size_t is unsigned, default type is signed int.
- when some expression uses signed and unsigned values, signed are
converted to unsigned, or something like that ...

However,
Converting signed to unsigned and vice versa is always potentially
broken if there is no reliable way to ensure bit 31 is zero.
So, architectures should not allow to convert SIGNED to UNSIGNED and vice
versa when bit 31 is set and generate an arithmetic EXCEPTION.
This would be quite sane, but do you think that it will really help?

> Seems to me the compiler actually caught a bug in your understanding of C.

The C language have had success because it is very permissive.
People who want to use a strict language should switch to COBOL in
my opinion.

Gerard.