comp.lang.c
[Top] [All Lists]

Re: value of the constant expression 1<<(1?1:1) < 0x9999

Subject: Re: value of the constant expression 1<<(1?1:1) < 0x9999
From: Francois Grieu
Date: Tue, 29 Apr 2008 21:32:20 -0700 PDT
Newsgroups: comp.lang.c

On 30 avr, 00:53, Keith Thompson <ks...@xxxxxxx> wrote:
> Francois Grieu <fgr...@xxxxxxxxx> writes:
> > one of my C compiler (Keil C51) evaluates the constant expression
> >    1<<(1?1:1) < 0x9999
> > to the value 0 [typo fixed]
>
> > // this returns 0, much to my surprise
> > unsigned char bug4_a(void)
> >    {
> >    return 1<<(1?1:1) < 0x9999;
> >    }
>
> > Can this find a satisfactory explanation under some definition of the
> > C language ?
>
> The behavior is inconsistent with the C standard.  (If Keil C51 claims
> to conform, it's a bug; if it doesn't, it may or may not be a bug,
> depending on what, if anything, its documentation says).

It is supposed to be "a complete implementation of the ANSI standard
for the C language", without mention of version, so I guess C89. There
is a section on "Differences from ANSI C", with no relevant entries.

> I'll assume that types int and unsigned int are 16 bits.

Yes.

> 1<<(1?1:1) has the value 2 and is of type int.

Yes. 1 is signed, thus 1<<.. is.

> 0x9999 has the value 39321 and is of type unsigned int.

Yes.

> The "usual arithmetic conversions" are applied to the operands of "<".
> This converts the left operand, 2, from int to unsigned int.

Thanks. That was the part I'm never sure in on standards before C99.

> So the expression 1<<(1?1:1) < 0x9999 is equivalent to 1U < 39321U,
> which yields the int value 1.  The return statement converts this to
> unsigned char, yielding (unsigned char)1.
>
> My guess is that a bug in the compiler is causing it to do the "usual
> arithmetic conversions" incorrectly in this case.  It's probably
> converting the right operand to signed int rather than converting the
> left operand to unsigned int, changing the comparison:
>     (int)2 < (unsigned)39321
> to
>     (int)2 < (int)-26215
> which yields 0.

Yes. However the fun thing is that the problem occurs only if
the ?: operator is used.
   (int)2 < (unsigned)39321     gives 1
   1<<(1?1:1)<39321             gives 0
   1<<1      <39321             gives 1
   (1?2:2)   <39321             gives 0

> Try replacing 0x9999 with 0x7fff and 0x8000 and see what happens.

Problem disapears.


Thanks, we found a compiler bug. I'll report it.

   Francois Grieu

<Prev in Thread] Current Thread [Next in Thread>
Privacy Policy