> Pedro Izecksohn <[EMAIL PROTECTED]> wrote:
> > If "The integer promotions preserve value including sign."

There are several 'promotion' rules at play in C (and C++.)

For integers with a 'rank' less than int, if the range of
the integer type fits into the range of int, then that
type will promote to int, if it is promoted. If the
range won't fit into an int, it will be promoted to an
unsigned int.

More precisely, if USHRT_MAX <= INT_MAX, then an unsigned
short that is subject to integral promotion will promote
to an int; otherwise, it will promote to an unsigned int.

Aside: arithmetic promotion occurs when the promoted types
don't match. For instance, if you multiplying an unsigned
int by an int, then the int will be promoted to unsigned
int.

Consider the test: (-1 < (unsigned short) 1)

Whilst intuitively it should always be true, there are
many implementations where it is false!

> > #include <stdio.h>
> >
> > int main (void) {
> > unsigned short int a;
> > unsigned long long int b, c;
> > a = -1;
> > b = (a*a);

Here's a table of what a will promote to, and the type of
a * a, dependant on the maximum values of unsigned short,
int and unsigned int:

   USHRT_MAX    INT_MAX      UINT_MAX       a * a
  ------------ ----------- ------------ --------------
  0xFFFF       0x7FFF       0xFFFF       unsigned int
  0xFFFF       0x7FFFFFFF   0xFFFFFFFF       int
  0xFFFFFFFF   0x7FFFFFFF   0xFFFFFFFF   unsigned int

The respective values of a * a for the three cases will
be: 1, overflow and 0xFFFE0001. In the overflow case,
the behaviour is undefined, so the compiler can do
whatever it wants.

But, if we pretend that we have the usual vanilla twos-
complement behaviour, the resulting int will be -131071.

Now when that value is converted to an unsigned integer
type, the value produced will be converted modulu one
more than the maximum value for that unsigned type.

If we suppose that unsigned long long has the range
0..0xFFFFFFFFFFFFFFFF, then the result value will be
0xFFFFFFFFFFFE0001 (in decimal 18446744073709420545.)

"Paul Herring" <[EMAIL PROTECTED]> wrote:
> Here you're multiplying two shorts.

There's no short in sight.

> > c = ((unsigned int)a*(unsigned int)a);
> 
> Here you're multiplying two ints.

There's no int in sight either.

I sounds like I'm overly nitpicking, but when it comes to
promotion rules, you need to be _very_ specific about type,
including signedness.

> Clearly, on your compiler, shorts are a different size
> to ints.

Now I will be overly nitpicking. :-) The size (in the
sizeof sense) is irrelevant. The _range_ of values is
what is crutial.

> > printf ("Why %llx != %llx ?\n", b, c);
[Why fffffffffffe0001 != fffe0001 ?]

Assuming UINT_MAX is 0xFFFFFFFF, 0xFFFFu * 0xFFFFu is
0xFFFE0001. Storing that positive 32-bit value into a
64-bit unsigned type isn't going to change the value!

Unsigned integers do not get sign-extended when promoted
to wider unsigned integer types. Why? Because there is
no sign to extend!

> > return 0;
> > }

I believe you have the usual two problems.

First, you believe promotion works from the outside in.
In other words, the type of the variable you're assigning
to will influence the types and promotion of the expression
on the right hand side. They won't. It works from the
inside out.

Secondly, you've probably been confused by 'hex' output in
combination with badly written books that encourage you to
think of representations, rather than in terms of values.

The C (and C++) languages convert numbers in terms of
values and type, not representations.

Unfortunately, some authors are so fascinated by the concept
of representation, particularly twos-complement, that they
forget that it's entirely _irrelevant_ when explaining how
integers work in C!

-- 
Peter

Reply via email to