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

F

Francois Grieu

Hello,

one of my C compiler (Keil C51) evaluates the constant expression
1<<(1?1:1) < 0x9999
to the value 1.

// 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 ?


Note: I still get 0 for

return 1<<(1?1:1) < (unsigned)0x9999;

return 1<<(unsigned char)(1?1:1) < 0x9999;

but I get 1 (as I expect) for

return 1<<(1) < 0x9999;

return (unsigned)1<<(1?1:1) < 0x9999;

return 1u<<(1?1:1) < 0x9999;

return 1<<(1?1:1) < 0x7777;

return 1<<(1?1:1) == 2;

#if 1<<(1?1:1) < 0x9999
return 1;
#else
return 0;

TIA,

Francois Grieu
 
P

Peter Nilsson

Francois said:
Hello,

one of my C compiler (Keil C51) evaluates the constant expression
1<<(1?1:1) < 0x9999
to the value 1.

Correct...

1 << (1?1:1) < 0x9999
(1 << (1?1:1)) < 0x9999
(1 << 1) < 0x9999
2 < 0x9999
1
// 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 ?
No.

Note: I still get 0 for

return 1<<(1?1:1) < (unsigned)0x9999;

return 1<<(unsigned char)(1?1:1) < 0x9999;

Integer promotion must be applied, but it is incidental. They
should all return 1 on a conforming implementation.
 
K

Keith Thompson

Francois Grieu said:
one of my C compiler (Keil C51) evaluates the constant expression
1<<(1?1:1) < 0x9999
to the value 1.

// 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).

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

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

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

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

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.

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

[snip]
 
P

Peter Nilsson

Keith said:
...
I'll assume that types int and unsigned int are 16 bits.

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

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

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

So the expression 1<<(1?1:1) < 0x9999 is equivalent to
1U < 39321U,

ITYM: 2U < 39321U
 
F

Francois Grieu

I am as tired as my cimpiler. Should have said

one of my C compiler (Keil C51) evaluates the constant expression
1<<(1?1:1) < 0x9999
to the value 0.

Thje rest was hopefully correct.

Francois Grieu
 
F

Francois Grieu

Francois Grieu said:
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
 
F

Francois Grieu

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

Problem disapears for 0x7fff but remain with 0x8000.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,773
Messages
2,569,594
Members
45,119
Latest member
IrmaNorcro
Top