integral promotion, arithmetic conversion, value preserving, unsigned preserving???

T

TTroy

Hello, I'm relatively new to C and have gone through more than 4 books
on it. None mentioned anything about integral promotion, arithmetic
conversion, value preserving and unsigned preserving. And K&R2
mentions "signed extension" everywhere.

Reading some old clc posts, I've beginning to realize that these books
are over-generalizing the topic. I am just wondering what the
difference between the following pairs of terms are:

1) Integral promotion vs. Arithmetic Conversion
2) Value Preserving vs. Unsigned Preserving

I've read many, many old posts from c.l.c that referred to those 4
terms constantly.. this is what I think they mean:

Integral Promotion
===================
All chars and shorts are promoted to int(signed) before any operating
is done on them. If an unsigned short has the same bit-size as int,
then the promotion is to unsigned int.

Integral promotion is done as an intermediate step for all common
computations.

Ex:

char a = 9;
unsigned b = 4;

a = b + a; /* a and b both converted to int before addition */
/* the result is then converted back to char by the assignment */

So basically, integral promotion gurantees that all intermediate
computations are dealt with nothing "lower" than an int. Am I right?

-
Artihmetic Promotion
=====================
If the variables involved in an arithmetic operation are all at least
int, then "level" priorities take over.

The priority is : long double, double, float, long, int

If one variable involved in a binary operation is a higher "level" than
the other, the other is promoted to that same level.

After that, the next type of priority is also applied, based on
signed/unsigned.
If one variable is unsigned and the other is signed, the signed is
converted to unsigned.

Once all this is done, we go on with the binary operation to produce
the result. Am I right?

-
Value Preserving
================
I am very confused on this term. Does it mean that, say for example, a
conversion from an unsigned short to an int is done, and the value
stored in the unsigned short is larger than the maximum possible
positive number in an int, then the result is implementation defined.
If the value stored in unsigned short is less than the maximum
posssible positive number in an in, then the exact value will exit in
the int (guaranteed to have msb = 0).

What I don't get about value preserving rules is, whether they are
based on the actual value in variables(run time), or the POSSIBLE
RANGES of the INTEGERS(compile time)?

-
Unsigned Preserving
===================
I have a feeling this is a more strict rule (subset of Value
preserving) that implies 2's compliment. Where actual bit patters are
moved without change, as would be the case for 2's compliment.
-

Many many posts on these subjects have gone through clc's servers, but
they all deal with subsets of what I'm presenting here. If someone
could make a more comprehensive response (or possible add it to the FAQ
website), I think that would be a major help (especially when books
only mention "signed extension".. some don't mention anything.. they
just say "the value is converted"... looked at C89 draft.. little too
advanced for a beginner).

By the way, if one of you clc regulars write a book on C as thorough as
the responses you give, it would force all these phony book authors
into extinction.

[Many of the programmers at my workplace (where I'm an electronics guy)
draw a blank when I ask them about this :-( ]
 
R

Richard Bos

TTroy said:
Integral Promotion
===================
All chars and shorts are promoted to int(signed) before any operating
is done on them. If an unsigned short has the same bit-size as int,
then the promotion is to unsigned int.

Ditto for unsigned char. It's a rare occasion outside freestanding
implementations, though.
char a = 9;
unsigned b = 4;

a = b + a; /* a and b both converted to int before addition */
/* the result is then converted back to char by the assignment */

So basically, integral promotion gurantees that all intermediate
computations are dealt with nothing "lower" than an int. Am I right?

Yes. Unfortunately - I don't like this "feature".
Artihmetic Promotion
=====================
If the variables involved in an arithmetic operation are all at least
int, then "level" priorities take over.

The priority is : long double, double, float, long, int

If one variable involved in a binary operation is a higher "level" than
the other, the other is promoted to that same level.

After that, the next type of priority is also applied, based on
signed/unsigned.
If one variable is unsigned and the other is signed, the signed is
converted to unsigned.

Once all this is done, we go on with the binary operation to produce
the result. Am I right?

Half. What you've written is correct; but there are similar promotions
for the floating point types.

Richard
 
K

Kobu

Richard said:
Ditto for unsigned char. It's a rare occasion outside freestanding
implementations, though.

Integral Promotion

A char or a short (signed or not) may be used in an expression whenever
an integer may be used. If an int can represent all the values of the
original type, then the value is converted to int; otherwise the value
is converted to unsigned int.

=> To add to the OP: When this conversion is done, how many integral
variables are taken into consideration for the promotion at a time, and
what exactly "expression" means is what all explanations lack.

For example (sizeof(short)== 32, sizeof(int) == 32):

unsigned short a = -1;
signed short b = 45;
signed char c = -34;
unsigned char d = 21;
signed long f = SLONG_MAX;
int = e;

e = (a*b + c*d) * f;


Are all a,b,c,d considered against the intergral promotion rule at
once? Or is a&b treated as an independent promotion from c&d? Are all
integral promotions in the whole expression finished before any further
conversions (based on arirthmetic rules)? These are some of the
questions for which I haven't found enlightenment in K&R2 or the
standards (not experienced enough to make much sense of the standards).
 
P

Peter Nilsson

No. The standard says...

"If an int can represent all values of the original type, the
value is converted to an int; otherwise, it is converted to an
unsigned int."

Bit size is irrelevant. It's the _value_ range that is significant.

It's arguable whether a hosted implementation where
INT_MAX < UCHAR_MAX could ever be conforming.
Integral Promotion

A char or a short (signed or not) may be used in an expression
whenever an integer may be used. If an int can represent all the
values of the original type, then the value is converted to int;
otherwise the value is converted to unsigned int.

=> To add to the OP: When this conversion is done, how many
integral variables are taken into consideration for the promotion
at a time, and what exactly "expression" means is what all
explanations lack.

For example (sizeof(short)== 32, sizeof(int) == 32):

You have a machine with 32 byte integers! Whatever the size,
the range of integer types is constrained, but _not_ determined
by the size of the integer.

The expression...

sizeof(short) > sizeof(int)

....can theoretically evaluate to 1 on a hypothetical conforming
implementation.
unsigned short a = -1;
signed short b = 45;
signed char c = -34;
unsigned char d = 21;
signed long f = SLONG_MAX;

If you meant LONG_MAX, the later expression is a bad example
since the overflow results in undefined behaviour.

ITYM int e;
e = (a*b + c*d) * f;

Are all a,b,c,d considered against the intergral promotion rule at
once?
Yes.

Or is a&b treated as an independent promotion from c&d? Are all
integral promotions in the whole expression finished before any
further conversions (based on arirthmetic rules)?

Effectively, yes. Though an implementation can achieve this in
various ways behind the scenes. [For instance, for the above
expression, a given compiler may silently convert all the arguments
to long before performing any arithmetic operation, if it can
determine that this act won't change a required result.]
 
S

S.Tobias

TTroy said:
difference between the following pairs of terms are:
1) Integral promotion vs. Arithmetic Conversion
2) Value Preserving vs. Unsigned Preserving

Integral promotions deal only with one type and convert (one) short
type to int type. Arithmetic conversions always deal with two types
and convert (one or both) the "smaller" type to the "larger" type (their
purpose is to establish common type for the operands and the result).
I've read many, many old posts from c.l.c that referred to those 4
terms constantly.. this is what I think they mean:
Integral Promotion
===================
All chars and shorts are promoted to int(signed) before any operating
is done on them.

All short types, to signed or unsigned int, and only in certain cases,
not everywhere.
If an unsigned short has the same bit-size as int,
then the promotion is to unsigned int.

Yes. ("Bit-size" is called width.)
Integral promotion is done as an intermediate step for all common
computations.

char a = 9;
unsigned b = 4;
a = b + a; /* a and b both converted to int before addition */

Only a is promoted.
/* the result is then converted back to char by the assignment */

Yes, but this time this conversion is neither promotion nor usual
arithmetic conversion (UAC).

Perhaps more interesting case is this one:
char c;
long l;
c + l;
First c is promoted to (signed or unsigned) int type, and then UAC takes
place and c is converted again to (signed or unsigned) long type.
So basically, integral promotion gurantees that all intermediate
computations are dealt with nothing "lower" than an int. Am I right?

Basically yes.
-
Artihmetic Promotion
=====================

You mean: Usual arithmetic conversion.
If the variables involved in an arithmetic operation are all at least
int, then "level" priorities take over.
The priority is : long double, double, float, long, int

For integer types the "level" is called "rank". Into the above list
you could throw in long long and extended types.
If one variable involved in a binary operation is a higher "level" than
the other, the other is promoted to that same level.

Yes. And you should use "converted"; the word "promoted" is reserved...
well... for promotions of course. :)
After that, the next type of priority is also applied, based on
signed/unsigned.

No, this is done at the same time. See below.
If one variable is unsigned and the other is signed, the signed is
converted to unsigned.

No. This rule is called "unsigned preserving" (aka "signedness preserving")
and was rejected for the "value preserving" rule. See below.
Once all this is done, we go on with the binary operation to produce
the result. Am I right?
Yes.

-

Value and unsigned preserving conversion rules apply both to promotions
and UACs, so we have to consider them together. (Of course, they
apply only to integer types for only they have signedness property).
They are two options of how to perform conversions between signed and
unsigned types. The Standard has chosen value preserving, and rejected
unsigned preserving rule.

Unsigned preserving rule
Whenever one operand is unsigned, all operands are converted to unsigned
version of the target type.
eg.:
promotion:
signed char -> int
unsigned char -> unsigned int
UAC:
unsigned int + long -> unsigned long + unsigned long
Unsigned preserving rule seems simpler and more predictable, but
the Standard has rejected it and it has never applied (only before
the Standard, it's in K&R1).

Value preserving rule
This rule works mostly the same as in unsigned preserving, with one
exception: when the "smaller" type is unsigned and the "larger" type
is signed.
promotion:
unsigned char -> (signed/unsigned) int
UAC:
unsigned int + long -> (s/u) long + (s/u) long
The rule says that:
if range(unsigned shorter) c range(signed longer)
convert (unsigned shorter) to (signed longer)
otherwise
convert both to (unsigned longer).
(range(type) is set of all possible values of type, 'c' means inclusion.)
(Note that in the first case the conversion unsigned->singed is well
defined, cf. 6.3.1.3.)

To illustrate this rule graphically (promotion only):

USHRT_MAX
-I--------------0---S-------------I---> promote short to int
INT_MIN INT_MAX

USHRT_MAX
-------I--------0--------I--------S---> promote short to unsigned
INT_MIN INT_MAX

Value preserving rule is what the Standard has chosen since the beginning.

Which of these rules is better is a matter of past discussions.
No doubt, "value unsigned preserving Chris Torek" are the best
keywords to find them. I don't have my opinion on this issue yet.

Value Preserving
================
I am very confused on this term. Does it mean that, say for example, a
conversion from an unsigned short to an int is done, and the value
stored in the unsigned short is larger than the maximum possible
positive number in an int, then the result is implementation defined.
If the value stored in unsigned short is less than the maximum
posssible positive number in an in, then the exact value will exit in
the int (guaranteed to have msb = 0).

When USHRT_MAX > INT_MAX, then promote to unsigned.
If USHRT_MAX <= INT_MAX, promote to int.
This is not implementation defined. The width of types is implementation
defined, so we may say that the result is indirectly implementation
defined, but it strictly depends on the ranges of both types.
What I don't get about value preserving rules is, whether they are
based on the actual value in variables(run time), or the POSSIBLE
RANGES of the INTEGERS(compile time)?

Of course, possible ranges.
-
Unsigned Preserving
===================
I have a feeling this is a more strict rule (subset of Value
preserving)

It's not a subset, both rules are mostly the same, they differ
only at one point.
that implies 2's compliment.
Where actual bit patters are
moved without change, as would be the case for 2's compliment.

Neither rule concerns the representation. Unsigned preserving demands
only that "unsigned" always wins, ie: unsigned + long -> both
to unsigned long, always and without exception.
-
[snip]
only mention "signed extension"..

"Sign extension" is about converting values (which is part of conversion
operation) in binary representation and it doesn't directly come into
what has been said above. This sort of applies _after_ you have
established what the target type is.
... looked at C89 draft.. little too
advanced for a beginner).

I know that part (I think of 6.3.1 in C99) is not easy to read,
but it is the most accurate explanation I have come across. Read it
twice a day, after two weeks it'll seem plain obvious to you. :)
 
S

S.Tobias

Peter Nilsson said:
Kobu wrote:
If you meant LONG_MAX, the later expression is a bad example
since the overflow results in undefined behaviour.
ITYM int e;

Of course all promotions can be done at the start, because the
results of arithmetic operators are int or above and there's nothing
to promote afterwards (unless there's a cast to a short type
later on the way).

I got lost here, but I think he means UACs at this point.
Effectively, yes. Though an implementation can achieve this in
various ways behind the scenes. [For instance, for the above
expression, a given compiler may silently convert all the arguments
to long before performing any arithmetic operation, if it can
determine that this act won't change a required result.]

I haven't considered exactly the expression, but the answer in genaral
seems to me "No":
unsigned u1, u2;
unsigned long ul;
u1 + u2 + ul;
First u1 and u2 are added. If the result may overflow in unsigned type.
Then the result is converted to unsigned long and ul is added. If all
operands were converted at the start before arithmetic operations
the resulting value might be different.
 
K

kiru.sengal

All short types, to signed or unsigned int, and only in certain cases,
not everywhere.

It's ridiculous how integral promotions done. The promotions vary
system to system. To me a "rule" like this shouldn't have an IF
STATEMENT attached to it (IF it fits, plug it into a signed int,
otherwise stuff it into an unsigned int), thus we have to live with the
confusions of both experts and beginners. Being someone who works with
8bit, 16bit, 32bit and 64bit micros, this really irritates me - only
way to write portable code is with extra-cautious casting or
preprocessor tricks.
 
L

Luke Wu

TTroy said:
Hello, I'm relatively new to C and have gone through more than 4 books
on it. None mentioned anything about integral promotion, arithmetic
conversion, value preserving and unsigned preserving. And K&R2
mentions "signed extension" everywhere.

Reading some old clc posts, I've beginning to realize that these books
are over-generalizing the topic. I am just wondering what the
difference between the following pairs of terms are:

1) Integral promotion vs. Arithmetic Conversion
2) Value Preserving vs. Unsigned Preserving

I've read many, many old posts from c.l.c that referred to those 4
terms constantly.. this is what I think they mean:

Integral Promotion
===================
All chars and shorts are promoted to int(signed) before any operating
is done on them. If an unsigned short has the same bit-size as int,
then the promotion is to unsigned int.

Integral promotion is done as an intermediate step for all common
computations.

Integral Promotion is not a "first pass" that is done on operands
before arithmetic conversions. Instead, it's a part of arithmetic
conversions (one of the steps).

Arithmetic Conversion (C89/90) follows like this:

1. If either operand is long double, the other is converted to long
double.
2. Otherwise, if either operand is double, the other is converted to
double.
3. Otherwise, if either operand is float, the other is converted to
float.
4. Otherwise, the integral promotions are performed on both operands;
then if either operand is unsigned long int, the other is converted to
unsigned long int.
5. Otherwise, if one operand is long int and the other is unsigned int,
the effect depends on whether a long int can represent all values of an
unsigned int; if so, the unsigned int operant is converted to long int;
if not, both are converted to unsigned long int.
6. Otherwise, if one operand is long int, the other is converted to
long int.
7. Otherwise, if either operand is unsigned int, the other is converted
to unsigned int.
8. Otherwise, both operands have type int.


If you look at step #4 in arithmetic conversions, you will find actions
pertaining to integral promotions. So Integral promotions only occur
if none of the other operands are of a floating point type (float,
double, long double). If the other operand is of a floating point
type, there is no integral promotion. If the other operand is not of a
floating point type, then all operands are first converted to a
minimum of (signed int or unsigned in), then the rest of the integer
related arithmetic conversions are done.

So, INTEGER PROMOTIONS are ONE STEP in ARITHMETIC PROMOTIONS (and if
there are floating point types involved, they aren't even the first
step).


Ex:

char a = 9;
unsigned b = 4;

a = b + a; /* a and b both converted to int before addition */
/* the result is then converted back to char by the assignment */

So basically, integral promotion gurantees that all intermediate
computations are dealt with nothing "lower" than an int. Am I right?

Assignments obey different rules (neither Arithmetic Conversions or
Integer Promotions apply).

in a statement like: a = b;
All that happens is b is coerced to a's type, doesn't matter who has a
higher rank or whether or no b is at least an int.
 
L

Luke Wu

Peter said:

No, not yes. All of them are not considered at once. First of all,
integral promotion is not an independent consideration, it's part of
the greater Usual Arithmetic Conversions (which includes floating
conversion, integral promotion, integer conversions - in that order).

The compiler will effectively look at the e = (a*b + c*d) * f
expression in steps, as can be explained by this parse tree:

.. =
.. / \
.. e *
.. / \
.. f +
.. / \
.. * *
.. / \ / \
.. a b c d

As you can see, at any instant, the compiler is dealing with only 1
operator and 2 operands. This smallest sub-expression is what the
compiler performs UAC on (following the steps I outlined in the
previous post). So let's say our system has the following
characteristic: USHRT_MAX > INT_MAX (unsigned short's range can't fit
in a signed integer).
Also assume that a & d are characters, b is a signed short and d is an
unsigned short.

So the compiler will consider each smalled sub expression
independently... so let's say the compiler deals with the a * b
subexpression first, since there are no floating point types, the first
step of UAC that applies to a * b is integral promotions. Since the
types of both a & b can fit in a signed int, they are promoted to a
signed int (which will be the result of the a * b sub expression). At
that point, no further steps of UAC apply, we're done for now.

Then let's say the compiler looks at c * d (it could have done this
before looking at a * b), the first step of UAC that applies to c * d
is integral promotions, since d is an unsigned short and USHRT_MAX >
INT_MAX, both c & d are converted to unsigned int, and that is the type
of the result. At that point, no futher steps of UAC apply, we're done
for now.

The next step would be to consider the sub expression held together by
the + in the tree (addition of the two results we've figured out from
now). Thus, we have the addition of a signed int and an unsigned int.
The first step of UAC that applies to this sub-expression is the
converstion of the signed int to the unsigned int, which will be the
type of the result.

Then we (or compiler) consider the top-most * in the tree, which
multiplies our result from just above with f. The first part of UAC
that applies here is the convesion of our result from above (unsigned
int) to float, which will be the type of our result. At that point, no
further steps of UAC apply (don't even have to consider integral
promotion).

So this is how we proceed up the tree, only looking at each smallest
sub expression (2 operands and 1 operator) when considering UAC. When
we reach the = operationg, UAC has no effect on it and conversion of
the right side's operands is made to match the type of the left operand
(e).

So this is how Integral Promotions, UAC, etc. apply to large
expressions. Compiler doesn't necessarily have to do everything
exactly like this. It can do it any way it wants, but it has to match
the behaviour we get from analysing expressions like this. You can't
look at a large expression and just say "all the chars, shorts,
bit-fields will be converted to ______ int" (where ______ is signed or
unsigned). Some could be converted in intermediate steps to unsigned
int, some could be converted in intermediate steps to signed int. They
are taken into consideration in pairs, and integral promotion is only
one consideration amongt many that make up UAC (if one of the operands
in a smallest sub-expression is a floating point type, integral
promotion will play no part with either operand).
 
T

TTroy

Luke said:
No, not yes. All of them are not considered at once. First of all,
integral promotion is not an independent consideration, it's part of
the greater Usual Arithmetic Conversions (which includes floating
conversion, integral promotion, integer conversions - in that order).

The compiler will effectively look at the e = (a*b + c*d) * f
expression in steps, as can be explained by this parse tree:

. =
. / \
. e *
. / \
. f +
. / \
. * *
. / \ / \
. a b c d

As you can see, at any instant, the compiler is dealing with only 1
operator and 2 operands. This smallest sub-expression is what the
compiler performs UAC on (following the steps I outlined in the
previous post). So let's say our system has the following
characteristic: USHRT_MAX > INT_MAX (unsigned short's range can't fit
in a signed integer).
Also assume that a & d are characters, b is a signed short and d is an
unsigned short.

So the compiler will consider each smalled sub expression
independently... so let's say the compiler deals with the a * b
subexpression first, since there are no floating point types, the first
step of UAC that applies to a * b is integral promotions. Since the
types of both a & b can fit in a signed int, they are promoted to a
signed int (which will be the result of the a * b sub expression). At
that point, no further steps of UAC apply, we're done for now.

Then let's say the compiler looks at c * d (it could have done this
before looking at a * b), the first step of UAC that applies to c * d
is integral promotions, since d is an unsigned short and USHRT_MAX >
INT_MAX, both c & d are converted to unsigned int, and that is the type
of the result. At that point, no futher steps of UAC apply, we're done
for now.

The next step would be to consider the sub expression held together by
the + in the tree (addition of the two results we've figured out from
now). Thus, we have the addition of a signed int and an unsigned int.
The first step of UAC that applies to this sub-expression is the
converstion of the signed int to the unsigned int, which will be the
type of the result.

Then we (or compiler) consider the top-most * in the tree, which
multiplies our result from just above with f. The first part of UAC
that applies here is the convesion of our result from above (unsigned
int) to float, which will be the type of our result. At that point, no
further steps of UAC apply (don't even have to consider integral
promotion).

So this is how we proceed up the tree, only looking at each smallest
sub expression (2 operands and 1 operator) when considering UAC. When
we reach the = operationg, UAC has no effect on it and conversion of
the right side's operands is made to match the type of the left operand
(e).

So this is how Integral Promotions, UAC, etc. apply to large
expressions. Compiler doesn't necessarily have to do everything
exactly like this. It can do it any way it wants, but it has to match
the behaviour we get from analysing expressions like this. You can't
look at a large expression and just say "all the chars, shorts,
bit-fields will be converted to ______ int" (where ______ is signed or
unsigned). Some could be converted in intermediate steps to unsigned
int, some could be converted in intermediate steps to signed int. They
are taken into consideration in pairs, and integral promotion is only
one consideration amongt many that make up UAC (if one of the operands
in a smallest sub-expression is a floating point type, integral
promotion will play no part with either operand).

If that is the case, I'm never using a short ever in my life. Why would
anyone use a short?????? Such variability and doubt for large
expressions (and the variability is multiplied along every step of the
computation)!!!!!
 
A

Alex Fraser

[snip]
Integral Promotion is not a "first pass" that is done on operands
before arithmetic conversions. Instead, it's a part of arithmetic
conversions (one of the steps).

Arithmetic Conversion (C89/90) follows like this: [snip]
If you look at step #4 in arithmetic conversions, you will find actions
pertaining to integral promotions. So Integral promotions only occur
if none of the other operands are of a floating point type (float,
double, long double). If the other operand is of a floating point
type, there is no integral promotion.

Are there any circumstances where performing all promotions as a "first
pass" would make a difference? I don't think so.

Alex
 
L

Luke Wu

Alex said:
[snip]
Integral Promotion is not a "first pass" that is done on operands
before arithmetic conversions. Instead, it's a part of arithmetic
conversions (one of the steps).

Arithmetic Conversion (C89/90) follows like this: [snip]
If you look at step #4 in arithmetic conversions, you will find actions
pertaining to integral promotions. So Integral promotions only occur
if none of the other operands are of a floating point type (float,
double, long double). If the other operand is of a floating point
type, there is no integral promotion.

Are there any circumstances where performing all promotions as a "first
pass" would make a difference? I don't think so.

Alex

I do think so.

Example:
Assume USHRT_MAX > INT_MAX.

and assume an expression like this (names describe their types)

doub * shrt + ushrt * int

If one was to consider integral promotion as a first pass on all
variables in this larger expression, they'll notice ushrt and shrt
(sub-int ranks). Since ushrt's range can't fit inside int's range,
they will promote those variables to unsigned int.

Once again, that would promote both shrt and ushrt to unsigned int.
Suppose shrt originally had a small negative number. It would be
promoted to a large positive number.

Then continuing on, that variable would be converted to double (still a
large positive number). So considering all sub-int variables at once
as a "first pass" produces a large positive floating point for shrt,
before it's multiplied with doub.

What really should happen is, doub * shrt is treated separately from
ushrt * int. shrt will be promoted directly to double, and it's small
negative value will be preserved (because conversions to floating point
type happen before integral promotion comes into consideration). Even
if the other operand in each sub-expression wasn't a floating point
type, treating each sub-expression differently still allows different
variables to be promoted to either signed or unsigned int (then later
on they could meet floating point types, which would promote them
directly to those types, without them ever having a common integral
type!!!). This is how value preserving compilers work (I hate it, it's
disgusting, but we can't ignore it).

If you read the previous posts in this thread, some posters were
assuming that ALL SUB-INT VARIABLES IN AN EXPRESSION BELOW 'INT' RANK
ARE PROMOTED TOGETHER AS A FIRST PASS, TO THE SAME TYPE (EITHER SIGNED
INT OR UNSIGNED INT). As you can see, following their assumption can
produce different results.

This is why C's conversion mechanisms (using value preserving) are
--------!!!!
 
A

Alex Fraser

Luke Wu said:
Alex said:
Are there any circumstances where performing all promotions as a
"first pass" would make a difference? I don't think so.

I do think so.

Example:
Assume USHRT_MAX > INT_MAX.

and assume an expression like this (names describe their types)

doub * shrt + ushrt * int

If one was to consider integral promotion as a first pass on all
variables in this larger expression, they'll notice ushrt and shrt
(sub-int ranks). Since ushrt's range can't fit inside int's range,
they will promote those variables to unsigned int. [snip]
If you read the previous posts in this thread, some posters were
assuming that ALL SUB-INT VARIABLES IN AN EXPRESSION BELOW 'INT' RANK
ARE PROMOTED TOGETHER AS A FIRST PASS, TO THE SAME TYPE (EITHER SIGNED
INT OR UNSIGNED INT).

I don't think anyone meant to suggest that all promotions should be "to the
same type". At least, I didn't.

In your example, if all promotions were performed first, the result would
always be the same provided that converting the value of shrt to double
always gives the same value (of type double) as promoting to int, and then
converting that int value to double.

Alex
 
L

Lawrence Kirby

On Sat, 29 Jan 2005 16:53:59 -0800, TTroy wrote:

....
If that is the case, I'm never using a short ever in my life. Why would
anyone use a short?????? Such variability and doubt for large

short always promotes to int, it is unsigned short that is the problem, as
well as unsigned character types.
expressions (and the variability is multiplied along every step of the
computation)!!!!!

There are arguably 2 possible uses for short

1. To save space compared to potentially larger types such as int. This
tends only to be useful for array elements and structure members.

2. To get a type with a specific size or representation. Of course C
itself doesn't make exact guarantees in this respect so code that
does this is non-portable.

Lawrence
 
L

Lawrence Kirby

On Sat, 29 Jan 2005 03:05:47 +0000, S.Tobias wrote:

....
Effectively, yes. Though an implementation can achieve this in
various ways behind the scenes. [For instance, for the above
expression, a given compiler may silently convert all the arguments
to long before performing any arithmetic operation, if it can
determine that this act won't change a required result.]

I haven't considered exactly the expression, but the answer in genaral
seems to me "No":
unsigned u1, u2;
unsigned long ul;
u1 + u2 + ul;
First u1 and u2 are added. If the result may overflow in unsigned type.
Then the result is converted to unsigned long and ul is added. If all
operands were converted at the start before arithmetic operations
the resulting value might be different.

That's what "if it can determine that this act won't change a required
result" deals with.

Lawrence
 
B

Big K

Alex said:
Luke Wu said:
Alex said:
Are there any circumstances where performing all promotions as a
"first pass" would make a difference? I don't think so.

I do think so.

Example:
Assume USHRT_MAX > INT_MAX.

and assume an expression like this (names describe their types)

doub * shrt + ushrt * int

If one was to consider integral promotion as a first pass on all
variables in this larger expression, they'll notice ushrt and shrt
(sub-int ranks). Since ushrt's range can't fit inside int's range,
they will promote those variables to unsigned int. [snip]
If you read the previous posts in this thread, some posters were
assuming that ALL SUB-INT VARIABLES IN AN EXPRESSION BELOW 'INT' RANK
ARE PROMOTED TOGETHER AS A FIRST PASS, TO THE SAME TYPE (EITHER SIGNED
INT OR UNSIGNED INT).

I don't think anyone meant to suggest that all promotions should be "to the
same type". At least, I didn't.

In your example, if all promotions were performed first, the result would
always be the same provided that converting the value of shrt to double
always gives the same value (of type double) as promoting to int, and then
converting that int value to double.

Alex


I've always used the method that Alex is referring to (where I start
off by "assuming" that all integral promotions are done first on a case
by case basis), then continued on with UAC. I always thought this
would produce the same behaviour as the longer, more proper method
would. Can anyone confirm that there is no risk to treating large
expressions this way?
 
P

Peter Nilsson

What about it?
range,

It can fit on many implementations.

Only unsigned short will be promoted to unsigned int, if and only if
USHRT_MAX > INT_MAX; short _always_ promotes to int.
[snip]
If you read the previous posts in this thread, some posters were
assuming that ALL SUB-INT VARIABLES IN AN EXPRESSION BELOW 'INT'
RANK ARE PROMOTED TOGETHER AS A FIRST PASS,

This alternative is equivalent to the standard. [Note that the
promotion
does not apply in all expressions, e.g. operands of sizeof.]

Luke, so far only you have made that assumption in your statement
above.

The assumption is correct whenever the short value is within the range
of double.
I've always used the method that Alex is referring to (where I start
off by "assuming" that all integral promotions are done first on a case
by case basis), then continued on with UAC. I always thought this
would produce the same behaviour as the longer, more proper method
would. Can anyone confirm that there is no risk to treating large
expressions this way?

There is no risk. The complications occur with UAC, not integral
promotion. For example, consider...

unsigned short x = 1;
unsigned long y = -1 * x;

If USHRT_MAX <= INT_MAX, then y will be ULONG_MAX.

However, if USHRT_MAX > INT_MAX, then y will be UINT_MAX. Even though
the integral promotion of x preserves the value, since the new type
is unsigned int, arithmetic promotion will see -1 converted also
converted to unsigned int, yielding UINT_MAX.
 

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,755
Messages
2,569,537
Members
45,021
Latest member
AkilahJaim

Latest Threads

Top