avr-chat
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [avr-chat] Type promotion and shift operators


From: Michael Hennebry
Subject: Re: [avr-chat] Type promotion and shift operators
Date: Wed, 2 Feb 2011 14:39:12 -0600 (CST)
User-agent: Alpine 1.00 (DEB 882 2007-12-20)

On Wed, 2 Feb 2011, Rick Mann wrote:

On Feb 2, 2011, at 10:49:11, Michael Hennebry wrote:

On Wed, 2 Feb 2011, Rick Mann wrote:

On Feb 2, 2011, at 08:15:40, Michael Hennebry wrote:

On Wed, 2 Feb 2011, Rick Mann wrote:

I was working with some uint32_t variables, using shifts, like this:

uint32_t foo = 0;

for (...)
{
 uint32_t v = // some value between [0, 31)

 foo |= 1 << v;
            ^
The type of RHS is int regardless of the type of v.

}

This didn't work correctly for values of v greater than 15 until I changed the 
line to:

 foo |= 1UL << v;
            ^^^
The type of RHS is unsigned long regardless of the type of v.

From what I understand of C, it should've promoted 1 to long, but maybe it's a 
signed-vs-unsigned issue? What's happening on an ATmega644A with this code?

'Twas a quiet change.
the type of x<<y is now the type of x after the usual integer promotions.

So, it looks like this?

        foo = (int) ((long) 1 << v)

If foo is still uint32_t, don't coerce to int.

No, I wasn't proposing that as the code I should write. I was trying to codify what you said. 
You said, "the type of x<<y is now the type of x after the usual integer 
promotions":

C doesn't believe is doing arithmetic on chars or shorts.
Had x been a short it would have been promoted to int before the shift.
In principle, y could be promoted,
but it wouldn't affect the type of the result.

1) usual integer promotions (which I take to mean, in this case, the LHS is 
promoted to the size of RHS)
2) result of shift operation is type of LHS argument

Not sure what this means.
Will hope desired information is provided elsewhere.

That seems to say that my original expression:

        foo |= 1 << v;

The type of 1 << v is the type of 1 which is int.
At least for v in 0..14, this has well-defined semantics equivalent to
foo |= (int)(1 << v);
foo |= 1U << v;
has well-defined semantics for nonnegative v.
C doesn't require as much of signed types as it does of unsigned.

Behaves as if I had written this:

        foo |= (int) (((long) 1) << v);    // extra parens added for clarity

Which strikes me as terribly wrong.

It is wrong.
For v>=15, it definitely would have no well-defined semantics.
The conversion from signed long to signed int is not value-preserving.

When was this change adopted into the language?

Don't know.

--
Michael   address@hidden
"Pessimist: The glass is half empty.
Optimist:   The glass is half full.
Engineer:   The glass is twice as big as it needs to be."



reply via email to

[Prev in Thread] Current Thread [Next in Thread]