Subject: Re: bin/3902: gcc doesn't promote correctly to (off_t)
To: None <ignatios@cosinus.cs.uni-bonn.de, jtc@NetBSD.ORG, kleink@NetBSD.ORG>
From: der Mouse <mouse@Rodents.Montreal.QC.CA>
List: netbsd-bugs
Date: 07/22/1997 10:09:18
> >Synopsis:       gcc doesn't promote correctly to (off_t)

> lseek(fd, -sizeof(cbuf), SEEK_CUR);
> [seeks by 2^32-sizeof(cbuf) instead of -sizeof(cbuf)]

> Casting to (off_t) doesn't help.
> lseek(fd, (off_t)-sizeof(cbuf), SEEK_CUR);
> Casting to (long) helps:
> lseek(fd, (long)-sizeof(cbuf), SEEK_CUR);
> First casting to (off_t), then taking the negative value works:
> lseek(fd, -(off_t)sizeof(cbuf), SEEK_CUR);

This is not a bug in gcc; this is (depending on your point of view) a
bug in C or a bug in the code.

sizeof(cbuf) is a size_t, which is either unsigned int or unsigned
long, I don't know which and on a 32-bit machine it doesn't matter.
Negating this results in the "correct" bit-pattern but still with
unsigned type.  Casting to off_t (which is implicit in the call, thanks
to lseek's prototype) then zero-extends, because the smaller value has
unsigned type.

Casting to off_t outside the negation doesn't help because it's just
doing explicitly the conversion that's implicit in the call anyway.

Casting to long outside the negation helps because it converts the
unsigned 32-bit value to a signed 32-bit value, which is then
sign-extended when it's converted to an off_t.  (Incidentally, the fact
that this cast helps tells me you're on a machine where long is 32
bits, not (eg) an alpha.)

Casting to off_t inside the negation helps because it extends the value
to off_t size while it's still positive and thus its unsignedness
doesn't affect the result of the conversion.

To the extent that ANSI allows the existence of integral types longer
than long, this is how ANSI requires it to be done.  gcc is correctly
implementing the ANSI-mandated semantics.

					der Mouse

			       mouse@rodents.montreal.qc.ca
		     7D C8 61 52 5D E7 2D 39  4E F1 31 3E E8 B3 27 4B