Akinori MUSHA wrote:
> I observed gcc 2.95.4 and gcc 3.1 interpret (or maybe optimize) the
> following code differently (CFLAGS=-O):
>
> int main(void)
> {
> unsigned char i = 127;
> printf("%d\n", ((char)(i << 1)) / 2);
> return 0;
> }
>
Cool...
> gcc 2.95.4 says it's -1,
Promotion of operand to int; conversion to lvalue type after
the operation.
> whereas gcc 3.1 says it's 127.
Promotion of operand to lvalue type.
> On FreeBSD
> char should be signed, so I suspect it's a (optimization) bug of gcc
> 3.1 which should be fixed. Or we'll have to do a mass audit of the
> whole src tree to check and fix the similar expressions.
Technically, I think, because of the parenthesis, that GCC 2.95 is
right, and GCC 3.1 is wrong. Given that the conversion to "char"
is done prior to the division, it should happen first.
>From the assembly, it looks like 3.1 is treating "/2" as ">>1",
and illegally canceling out the "<<1" with the ">>1" *before* the
conversion. Or maybe it's the conversion to int that happens on
the stack value for a %d argument to printf...
Maybe one of out C standards people can define when the conversion
is defined to occur, so we can get a real ruling.
Note that:
int main(void)
{
unsigned char i = 127;
printf("%d\n", (char)((i << 1) / 2));
return 0;
}
...yields 127 on gcc 2.95, so it's definitely order of conversion
being totally screwed by gcc 3.1.
Basically, it's assuming commutability where it's not present.
> In any case, this behavior makes moused(8) return a stupid value of
> 127 when you roll the mouse wheel up under ps/2-sysmouse-intellimouse
> protocol. Attached is a patch that makes the whole expression look
> more logical and works around the above behavior at the same time.
[ ... ]
> - act->dz = ((char)(pBuf[5] << 1) + (char)(pBuf[6] << 1))/2;
> + act->dz = ((char)(pBuf[5] << 1) + (char)(pBuf[6] << 1)) >> 1;
This is *soooooooooo* counter intuitive that it's evil!
-- Terry
To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-current" in the body of the message