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

Discussion in 'C Programming' started by TTroy, Jan 28, 2005.

  1. TTroy

    TTroy Guest

    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 :-( ]
     
    TTroy, Jan 28, 2005
    #1
    1. Advertising

  2. TTroy

    Richard Bos Guest

    "TTroy" <> wrote:

    > 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
     
    Richard Bos, Jan 28, 2005
    #2
    1. Advertising

  3. TTroy

    Kobu Guest

    Richard Bos wrote:
    > "TTroy" <> wrote:
    >
    > > 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.
    >


    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).
     
    Kobu, Jan 29, 2005
    #3
  4. Kobu wrote:
    > Richard Bos wrote:
    > > "TTroy" <> wrote:
    > >
    > > > 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.


    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.

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


    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.

    > int = e;


    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.]

    --
    Peter
     
    Peter Nilsson, Jan 29, 2005
    #4
  5. TTroy

    S.Tobias Guest

    TTroy <> wrote:

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


    > Ex:


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

    --
    Stan Tobias
    mailx `echo LID | sed s/[[:upper:]]//g`
     
    S.Tobias, Jan 29, 2005
    #5
  6. TTroy

    S.Tobias Guest

    Peter Nilsson <> wrote:
    > Kobu wrote:


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


    > > int = e;


    > ITYM int e;


    > >
    > > e = (a*b + c*d) * f;
    > >
    > > Are all a,b,c,d considered against the intergral promotion rule at
    > > once?


    > Yes.


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

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


    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.

    --
    Stan Tobias
    mailx `echo LID | sed s/[[:upper:]]//g`
     
    S.Tobias, Jan 29, 2005
    #6
  7. TTroy

    Guest


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


    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.
     
    , Jan 29, 2005
    #7
  8. TTroy

    Luke Wu Guest

    TTroy wrote:
    > 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.
     
    Luke Wu, Jan 29, 2005
    #8
  9. TTroy

    Luke Wu Guest

    Peter Nilsson wrote:
    >
    > Kobu Selva wrote:
    > >
    > >
    > > unsigned short a = -1;
    > > signed short b = 45;
    > > signed char c = -34;
    > > unsigned char d = 21;
    > > signed long f = LONG_MAX;
    > > int = e;
    > >
    > > e = (a*b + c*d) * f;
    > >
    > > Are all a,b,c,d considered against the intergral promotion rule at
    > > once?

    >
    > Yes.
    >


    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).
     
    Luke Wu, Jan 30, 2005
    #9
  10. TTroy

    TTroy Guest

    Luke Wu wrote:
    > Peter Nilsson wrote:
    > >
    > > Kobu Selva wrote:
    > > >
    > > >
    > > > unsigned short a = -1;
    > > > signed short b = 45;
    > > > signed char c = -34;
    > > > unsigned char d = 21;
    > > > signed long f = LONG_MAX;
    > > > int = e;
    > > >
    > > > e = (a*b + c*d) * f;
    > > >
    > > > Are all a,b,c,d considered against the intergral promotion rule

    at
    > > > once?

    > >
    > > Yes.
    > >

    >
    > 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)!!!!!
     
    TTroy, Jan 30, 2005
    #10
  11. TTroy

    Alex Fraser Guest

    "Luke Wu" <> wrote in message
    news:...
    [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
     
    Alex Fraser, Jan 30, 2005
    #11
  12. TTroy

    Luke Wu Guest

    Alex Fraser wrote:
    > "Luke Wu" <> wrote in message
    > news:...
    > [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
    --------!!!!
     
    Luke Wu, Jan 30, 2005
    #12
  13. TTroy

    Alex Fraser Guest

    "Luke Wu" <> wrote in message
    news:...
    > Alex Fraser wrote:
    > > 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
     
    Alex Fraser, Jan 30, 2005
    #13
  14. 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
     
    Lawrence Kirby, Jan 31, 2005
    #14
  15. 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
     
    Lawrence Kirby, Jan 31, 2005
    #15
  16. TTroy

    Big K Guest

    Alex Fraser wrote:
    > "Luke Wu" <> wrote in message
    > news:...
    > > Alex Fraser wrote:
    > > > 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?
     
    Big K, Jan 31, 2005
    #16
  17. Big K wrote:
    > Alex Fraser wrote:
    > > "Luke Wu" <> wrote:
    > > > Alex Fraser wrote:
    > > > > 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


    What about it?

    > > > 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,

    It can fit on many implementations.

    > > > they will promote those variables to unsigned int.


    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.]

    > > > TO THE SAME TYPE (EITHER SIGNED INT OR UNSIGNED INT).


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

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


    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.

    --
    Peter
     
    Peter Nilsson, Jan 31, 2005
    #17
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Alexander Stippler
    Replies:
    6
    Views:
    434
    Rolf Magnus
    Oct 30, 2003
  2. Niels Dekker (no reply address)

    Usual arithmetic conversions + integral promotion for short?

    Niels Dekker (no reply address), May 19, 2004, in forum: C++
    Replies:
    10
    Views:
    1,948
    Niels Dekker (no reply address)
    May 22, 2004
  3. Fred Ma
    Replies:
    9
    Views:
    405
    Dave Thompson
    Feb 9, 2004
  4. Carsten Hansen

    Bit-fields and integral promotion

    Carsten Hansen, Jan 28, 2005, in forum: C Programming
    Replies:
    117
    Views:
    1,971
    Joe Wright
    Feb 8, 2005
  5. sarathy

    integer promotion and arithmetic conversion

    sarathy, Aug 16, 2006, in forum: C Programming
    Replies:
    6
    Views:
    537
Loading...

Share This Page