Integral promotion. 
Author Message
 Integral promotion.

I got a problem understanding the rules on integral promotion in
the C language:

Consider the following function:

short test(short x1, short x2);

int main(void)
{
  short result;
  result = test(1, 2);
  return 0;

Quote:
}

short test(short x1, short x2)
{
  short result;
  result = x1 + x2;  /* Warning:  '=' : conversion from 'int '                                
                         to 'short ', possible loss of data */
  return result;

Quote:
}

My compiler (Microsoft Visual C++ 4.0), automagically converts
my short-parameters to int's, even though all variables involved
are short. I know that the standard says that all arguments can
be converted to the biggest 'type' of all the arguments, but is
it correct that char's and short's always are promoted to int's,
without regard to the other arguments in the expression?

The reason I ask is that I am writing code that should be
portable from a 16-bits environment (where short and int are the
same size) to a 32-bits environment. (My 16-bits compiler does
not complain about the code).

--
Rune Huseby
2b | ~2b == ff



Sun, 02 Aug 1998 03:00:00 GMT  
 Integral promotion.
(I sent this as a reply by mail but am also posting it.)


Quote:
>I got a problem understanding the rules on integral promotion in
>the C language ...

The rules in C are a little over-complicated (they were once entirely
straightforward) but the complications mostly involve `unsigned'.

It seems a little odd that you mention `Visual C++ 4.0', which
sounds like a C++ compiler; C++ is an entirely different language
with entirely different subtleties.  (For instance, (sizeof 'x')
is always 1 in C++ but is typically 2 or 4 in C.)

Quote:
>Consider the following function:

>short test(short x1, short x2);

The prototype is important.

We can mostly ignore the (valid) main() you provided...

Quote:
>short test(short x1, short x2)
>{
>  short result;
>  result = x1 + x2;  /* Warning:  '=' : conversion from 'int '
>                         to 'short ', possible loss of data */
>  return result;
>}

Again, we have a prototype-style definition, so the declaration
and definition match.

`Old' (pre-ANSI) C always performed `the integral promotions' on
all parameters.  For this reason, ANSI/ISO C does the same with
parameters for which a prototype is not available -- this covers
both `functions without prototypes' and `functions whose prototype
ends in ", ..."', e.g., printf().  (This means that, for instance,
you can never pass a short to printf().  By the time printf()
receives it, the value has been converted to an int.)  In Old C,
if you defined a function like this:

        void func(i, s, c)
                int i;
                short s;
                char c;
        {
        }

the compiler would take the three `int's that it knew had been
passed (due to the integral promotions), put the first in `i',
narrow the second to `short' and put it in `s', and narrow the
third and put it in `c'.  This promotion and narrowing sometimes
needs extra instructions (it depends on the machine, and maybe
the type as well).

For efficiency and/or less-surprising behavior, ANSI C says that
prototyped parameters (as you have here) are not promoted.  (Many
compilers simply promote them at the caller, and then narrow them
before entering the function, just as for Old C, but they can now
avoid these steps in this case.)

Because ANSI C requires promotion for non-prototypes and non-promotion
for prototypes, it is important to make sure you never mix up the
two kinds of declarations and definitions when you use `narrow'
types (char, short, signed char, unsigned char, unsigned short,
and float).

Anyway, with all that out of the way, we have a correct declaration
and definition for function test(), with `x1', `x2', and `result' all
being `short'.

Now, the last hard part is the line:

        result = x1 + x2;

This takes the values in x1 and x2 (both of type (signed) short
and hence in the range [SHRT_MIN .. SHRT_MAX]), performs the
integral promotions (yeilding values of type (signed) int but still
in the range [SHRT_MIN .. SHRT_MAX]), and adds them.  At this
point, the sum still has type (signed) int and could potentially
be in the range [2*SHRT_MIN .. 2*SHRT_MAX].

Now, if `int' and `short' are the same width, a result that would
be outside the range [SHRT_MIN .. SHRT_MAX] is also outside the
range [INT_MIN .. INT_MAX], and the behavior is undefined (ANSI C
section 3.3, p. 39, ll. 15--17).

On the other hand, if `int's are wider than `short's, we are pretty
safe (maybe not completely safe, but pretty safe anyway) in assuming
that INT_MIN <= 2*SHRT_MIN and INT_MAX >= 2*SHRT_MAX.  Most likely
INT_MIN and INT_MAX are something like 65536 times bigger.  Either
way, the sum is not outside the representable range and the undefined
clause in 3.3 does not apply.

The final step is to convert the sum back to type `short'.  Here
things get a little fuzzy; comp.std.c has had arguments as to what
happens if the sum is `int', `int' is wider than `short', and the
sum is not representable as a `short'.  The Standard distinguishes
between `implicit' and `explicit' conversions, and this is an
`implicit' conversion (casts are the usual, perhaps the only, way
to write explicit conversions).  Some have argued that an explicit
conversion should never cause an overflow, but there seems to be
no wording in the standard to justify this position.  There appears
to be agreement that implicit conversion might overflow.  The
behavior on overflow would be undefined.

Your particular compiler is likely to ignore the overflow and
truncate the result (most compilers do, and the warning -- `possible
loss of data' -- suggests that yours does).

It is interesting, however, to note that if overflow will ever occur,
it will occur no matter whether the ranges of short and int coincide
or not.  The only thing that changes here is the exact operation that
overflows: the sum, or the implicit conversion in the assignment.

The compiler's warning suggests (but by no means guarantees) that
this particular compiler has wider `int's than `short's.  Since this
is comp.lang.c.moderated (as well as comp.std.c), it is reasonable
to ask whether the warning the compiler emits is `reasonable'.  I
think not, but this is purely my opinion.  The Standard itself allows
arbitrary warnings, so it is no help here.

Quote:
>my compiler (Microsoft Visual C++ 4.0), automagically converts
>my short-parameters to int's, even though all variables involved
>are short. I know that the standard says that all arguments can
>be converted to the biggest 'type' of all the arguments,

See the detailed explanation above :-)

Quote:
>but is it correct that char's and short's always are promoted to int's,
>without regard to the other arguments in the expression?

In expressions, yes.

Quote:
>The reason I ask is that I am writing code that should be
>portable from a 16-bits environment (where short and int are the
>same size) to a 32-bits environment. (My 16-bits compiler does
>not complain about the code).

Perhaps it should, since the sum itself can overflow here just as
easily as a conversion from a 32-bit-int sum to a 16-bit short
`result'.  Again, the Standard is no help here, and my personal
opinion is that a warning is unwarranted (because such a warning
should then be given for virtually every operator).

I would find an `assignment may truncate' warning appropriate, and
maybe even helpful, when the target of a complex expression has a
narrower type than at least one of the operands *before* promotion.
That is, if someone writes:

        short a, b, prod;

        prod = a * b;

I would object (mildly) to a warning, but if they had:

        int a;
        short b, prod;

        prod = a * b;

I would not.  In this case, I think an explicit truncation somewhere
should eliminate the warning, so that either:

        prod = (short)(a * b);

or:

        prod = (short)a * b;    /* not the same thing at all! */

should not warn.  But, again, this is simply my opinion.
--
In-Real-Life: Chris Torek, Berkeley Software Design Inc



Sun, 02 Aug 1998 03:00:00 GMT  
 Integral promotion.


Quote:
> I got a problem understanding the rules on integral promotion in
> the C language:

> short test(short x1, short x2);

> My compiler (Microsoft Visual C++ 4.0), automagically converts
> my short-parameters to int's, even though all variables involved
> are short. I know that the standard says that all arguments can
> be converted to the biggest 'type' of all the arguments, but is
> it correct that char's and short's always are promoted to int's,
> without regard to the other arguments in the expression?

This is news to me, but it seems that section 6.2.1.5 of the standard
says that the lowest integer type is an int. If I am going to buy these
things I suppose I ought to read them.

My reading is that
short result = x1 + x2; /* going from int to short, possible loss of data */

gives the "same" result mathematically as
short result = ( int ) x1 + ( int ) x2 ;
i.e. you assign an int to a short value. The results of this conversion
are ( I think ) implementation-defined if the short is signed.

Regards,
Dominic.

--
Dominic Feeley



Sun, 02 Aug 1998 03:00:00 GMT  
 Integral promotion.

<snip>
   This is news to me, but it seems that section 6.2.1.5 of the standard
   says that the lowest integer type is an int. If I am going to buy these
   things I suppose I ought to read them.

So are chars and shorts not `integer types'? Or are they higher than int?

<snip>
   are ( I think ) implementation-defined if the short is signed.

In which version of C is short unsigned?

Cheers
Tanmoy
--

Tanmoy Bhattacharya O:T-8(MS B285)LANL,NM87545 H:#9,3000,Trinity Drive,NM87544
Others see <gopher://yaleinfo.yale.edu:7700/00/Internet-People/internet-mail>,
<http://alpha.acast.nova.edu/cgi-bin/inmgq.pl>or<ftp://csd4.csd.uwm.edu/pub/
internetwork-mail-guide>. -- <http://nqcd.lanl.gov/people/tanmoy/tanmoy.html>
fax: 1 (505) 665 3003   voice: 1 (505) 665 4733    [ Home: 1 (505) 662 5596 ]



Mon, 03 Aug 1998 03:00:00 GMT  
 Integral promotion.

Quote:

>short test(short x1, short x2)
>{
>  short result;
>  result = x1 + x2;  /* Warning:  '=' : conversion from 'int '                                
>                         to 'short ', possible loss of data */
>  return result;
>}

Your compiler is right.  "Integral promotion" means that before anything
else happens to them in an arithmetic expression, signed char and short
promote to int, and unsigned char and unsigned short promote to unsigned int.
Your compiler has to be able to implement arithmetic on
        signed int              signed long
        unsigned int            unsigned long
but not on any other integral types.  Note in particular that in a system
where INT_MAX > SHRT_MAX loss of data really _is_ possible:

        short x1 = SHRT_MAX;
        short x2 = SHRT_MAX;
        short result = x1 + x2; /* OVERFLOW! */

On a 16-bit sloppy system, the chances are pretty good that you'd get
        result < 0
but on a 32-bit system, sloppy or not, this example must yield
        result > 0.
And remember, on a MIPS, Alpha, SPARC, 88k, &c there _is_ no 16-bit add
instruction; it _has_ to be done in 32-bit mode.

Yes, there are C compilers that generate code that raises an exception if
a signed integer overflow occurs.  I've used one.  It's *extremely* useful
because it's almost always a mistake.  If you really want wraparound, you
can use unsigned arithmetic.

Quote:
>The reason I ask is that I am writing code that should be
>portable from a 16-bits environment (where short and int are the
>same size) to a 32-bits environment. (My 16-bits compiler does
>not complain about the code).

Well, there's no way to get exactly the same set of warnings on every
system; a compiler can legitimately complain about the colour of your
eyes if it wants to, as long as it correctly translates the code.

It is really really worth investing in a 'lint' checker.  If you're using
a DOS system, I've heard good things about Gimpel's lint.
--
Election time; but how to get Labour _out_ without letting Liberal _in_?
Richard A. O'Keefe; http://www.cs.rmit.edu.au/~ok; RMIT Comp.Sci.



Mon, 03 Aug 1998 03:00:00 GMT  
 Integral promotion.

:I got a problem understanding the rules on integral promotion in
:the C language:
:
:Consider the following function:
:
:short test(short x1, short x2);
:
:int main(void)
:{
:  short result;
:  result = test(1, 2);
:  return 0;
:}
:
:short test(short x1, short x2)
:{
:  short result;
:  result = x1 + x2;  /* Warning:  '=' : conversion from 'int '                                
:                         to 'short ', possible loss of data */
:  return result;
:}
:
:My compiler (Microsoft Visual C++ 4.0), automagically converts
:my short-parameters to int's, even though all variables involved
:are short. I know that the standard says that all arguments can
:be converted to the biggest 'type' of all the arguments, but is
:it correct that char's and short's always are promoted to int's,
:without regard to the other arguments in the expression?

No.  Char's and int's will only be promoted to int's if an int can
represent all values of the original type.  Otherwise they will
be promoted to unsigned int's.  This process is called Integral
Promotion and is described in A6.1 of K&R II.  You should read
the entire section A.6 Conversions (less than three pages) and
pay special attention to A6.5 Arithmetic Conversions, particu-
larly if you are switching between difference environments.

The rules of dealing with one operand a long and the other an
unsigned, differ depending on whether all values of an unsigned
call be represented by a long.  They can be on most 16 bit
implementations (short=int=16-bit, long=32-bit), but cannot on
most 32 bit (short=16, int=long=32-bit).

:The reason I ask is that I am writing code that should be
:portable from a 16-bits environment (where short and int are the
:same size) to a 32-bits environment. (My 16-bits compiler does
:not complain about the code).

Since, as you state, short and int are the same size on your 16 bit
compiler, you can assign from signed int to signed short without
"possible loss of data."

Bill McCarthy

Wendell, NC  USA



Mon, 03 Aug 1998 03:00:00 GMT  
 Integral promotion.
:
: I got a problem understanding the rules on integral promotion in
: the C language:
:
: Consider the following function:
:
: short test(short x1, short x2);
:
: int main(void)
: {
:   short result;
:   result = test(1, 2);

The numbers 1 and 2 here are by convention considered by compiler to be ints (not
shorts).

:   return 0;
: }
:
: short test(short x1, short x2)
: {
:   short result;
:   result = x1 + x2;  /* Warning:  '=' : conversion from 'int '
:                          to 'short ', possible loss of data */
:   return result;
: }
:
: My compiler (Microsoft Visual C++ 4.0), automagically converts
: my short-parameters to int's, even though all variables involved
: are short. I know that the standard says that all arguments can
: be converted to the biggest 'type' of all the arguments, but is
: it correct that char's and short's always are promoted to int's,
: without regard to the other arguments in the expression?

Chars are converted to ints, because passing a byte (where char equals one byte in
size) is both inefficient and leads to difficulties in the receiving party (for
instance, to pass two chars would then pack them into one byte, which the receiver
would have to be able to handle).

:
: The reason I ask is that I am writing code that should be
: portable from a 16-bits environment (where short and int are the
: same size) to a 32-bits environment. (My 16-bits compiler does
: not complain about the code).

That's because in 16-bits, sizeof(int) == sizeof(short) in PC world.

Later,
 AriL
--
All my opinions are mine and mine alone.



Mon, 03 Aug 1998 03:00:00 GMT  
 Integral promotion.

:I got a problem understanding the rules on integral promotion in
:the C language:
:
:Consider the following function:
:
:short test(short x1, short x2);
:
:int main(void)
:{
:  short result;
:  result = test(1, 2);
:  return 0;
:}
:
:short test(short x1, short x2)
:{
:  short result;
:  result = x1 + x2;  /* Warning:  '=' : conversion from 'int '                                
:                         to 'short ', possible loss of data */
:  return result;
:}
:
:My compiler (Microsoft Visual C++ 4.0), automagically converts
:my short-parameters to int's, even though all variables involved
:are short.

The parameters for a prototyped function are not converted.  That is,
x1 and x2 remain type short int.  

When they are used in most expressions which expect an int type they
undergo integral promotion, regardless of the type of the other
operands.  

:I know that the standard says that all arguments can
:be converted to the biggest 'type' of all the arguments, but is
:it correct that char's and short's always are promoted to int's,
:without regard to the other arguments in the expression?

It depends on the usage, but usually yes.  Some exceptions would be
operand of sizeof, ++, --, and simple assignment.

Even though the operands are promoted in expressions, the compiler
might not actually expand the arguments if the end results are the
same.  In the example code, the compiler is free to perform the
addition using a short accumulation register, assuming the result,
when assigned to a short, is the same as would occur with promotion
and conversion to short int.

:The reason I ask is that I am writing code that should be
:portable from a 16-bits environment (where short and int are the
:same size) to a 32-bits environment. (My 16-bits compiler does
:not complain about the code).

If the code is written correctly and assumptions are not made about
the maximum values, e.g., that 1 << 16 == 0, you should be OK.

Thad



Mon, 03 Aug 1998 03:00:00 GMT  
 Integral promotion.

Quote:


>: short test(short x1, short x2);
>: int main(void)
>: {
>:   short result;
>:   result = test(1, 2);
>:   return 0;
>: }
>The numbers 1 and 2 here are by convention considered by compiler to be ints (not
>shorts).

Yes, but because a prototype is in scope for the function "test" they
are converted to the types of the parameters (as if by assignment), so
the compiler converts 1 and 2 to shorts before passing them.

Quote:
>: short test(short x1, short x2)
>: {
>:   short result;
>:   result = x1 + x2;  /* Warning:  '=' : conversion from 'int '
>:                          to 'short ', possible loss of data */
>:   return result;
>: }
>:
>: My compiler (Microsoft Visual C++ 4.0), automagically converts
>: my short-parameters to int's, even though all variables involved
>: are short. I know that the standard says that all arguments can
>: be converted to the biggest 'type' of all the arguments, but is
>: it correct that char's and short's always are promoted to int's,
>: without regard to the other arguments in the expression?

>Chars are converted to ints, because passing a byte (where char equals one byte in
>size) is both inefficient and leads to difficulties in the receiving party (for
>instance, to pass two chars would then pack them into one byte, which the receiver
>would have to be able to handle).

The mechanism of passing and how much space the parameters take up on
the stack (if one exists!) is a complete black box as far as the
standard goes.  It can turn them into hex and engrave the parameter
values on papyrus reeds and have the called function run an OCR to get
the values off for all the standard says.  But if the function
parameter is called a short in the function definition and the program
doesn't violate any constraints (the most likely one to break here would
be a new-style function definition called without a function declaration
in scope) then the parameters are shorts in the function body.  This is
true even on PC compilers that might not be conforming because of other
reasons.

Now what *really* happens here is described in the appendix of K&R2:
A6.1 Integral Promotion:  A character [...] may be used in an expression
wherever an integer may be used. [...] the value is converted to int;

[This article was posted to both comp.std.c and comp.lang.c.moderated.
For the former I ought to be quoting form the standard.  For the latter,
far more people have access to K&R2 to check things than the standard.]

So while

x1 and x2 are shorts and remain shorts regardless of how the compiler
sees fit to pass them to the "test" function, in the expression "x1 +
x2" there values are converted to ints.  Thus the type of "x1 + x2" is
an int and it is *this* that is being converted to a short during the
assignment to result.

The original poster was mostly right in the last sentence -- the values
of short variables in an expression are convert to int if an int can
hold all possible values, otherwise converted to an unsigned int.  It is
neither the arguments nor the parameters that are being converted.

-michael j zehr



Tue, 04 Aug 1998 03:00:00 GMT  
 Integral promotion.

Quote:


>Thus even in ANSI C, if this function is called this way:

>    extern short p, q, r, test(short,short);
>    r = test(p,q);

>the values from p and q are still converted from short to int and back
>to short.  

I find nothing in the Standard that states that the arguments undergo
integral promotions before being assigned to the function parameters.

Thad



Tue, 04 Aug 1998 03:00:00 GMT  
 Integral promotion.

writes:
<snip>


   >Thus even in ANSI C, if this function is called this way:
   >
   > extern short p, q, r, test(short,short);
   > r = test(p,q);
   >
   >the values from p and q are still converted from short to int and back
   >to short.  

   I find nothing in the Standard that states that the arguments undergo
   integral promotions before being assigned to the function parameters.

The way I read the standard (6.2.1.1):

``A char, a short int, or an int bit-field, or their signed or unsigned
varieties, or an enumeration type, may be used in an expression
wherever an int or unsigned int may be used. ...< describing integral
promotions >... these are called integral promotions.''

Seems to imply that whenever a value of type `int' is a possibility,
integral promotions always take place. Without enum types, I don't see
how this matters in a function call, as long as implementation defined
behaviour is reasonable (i.e. signed char->int->short is same as
signed char->short etc.)

For enums, I am confused. If an enum type is compatible with `long',
does integral _promotion_ narrow it to an int or unsigned int :-)?

Cheers
Tanmoy
--

Tanmoy Bhattacharya O:T-8(MS B285)LANL,NM87545 H:#9,3000,Trinity Drive,NM87544
Others see <gopher://yaleinfo.yale.edu:7700/00/Internet-People/internet-mail>,
<http://alpha.acast.nova.edu/cgi-bin/inmgq.pl>or<ftp://csd4.csd.uwm.edu/pub/
internetwork-mail-guide>. -- <http://nqcd.lanl.gov/people/tanmoy/tanmoy.html>
fax: 1 (505) 665 3003   voice: 1 (505) 665 4733    [ Home: 1 (505) 662 5596 ]



Wed, 05 Aug 1998 03:00:00 GMT  
 Integral promotion.

Quote:

> > Thus even in ANSI C, if this function is called this way:

> >       extern short p, q, r, test(short,short);
> >       r = test(p,q);

> > the values from p and q are still converted from short to int and back
> > to short.  


Quote:
> I find nothing in the Standard that states that the arguments undergo
> integral promotions before being assigned to the function parameters.

This is in 6.2.1.1/3.2.1.1, the passage which defines the integral
promotions.  It states that the promotions apply

#  in an expression wherever an int or unsigned int may be used.

Since the call test(1,2) is permissible, this means that p and q must
be promoted to int.  As noted in my previous posting, they are then
converted right back to short within the caller (since a prototype
was used), and the compiler can easily optimize this out.

Another example of this sort of thing is an assignment expression like
p=q, where p and q are short.  q is promoted to int, then demoted back
to short; since the value cannot change, the compiler optimizes out the
conversions.  If you write p=(short)q, then the same reason applies
to each of the expressions q and (short)q, and you end up with *two*
round-trip conversions which should be optimized out.
--

SoftQuad Inc., Toronto           but I forget what"     -- Rayan Zachariassen

My text in this article is in the public domain.



Wed, 05 Aug 1998 03:00:00 GMT  
 Integral promotion.

[snip]

Quote:
>So while
>x1 and x2 are shorts and remain shorts regardless of how the compiler
>sees fit to pass them to the "test" function, in the expression "x1 +
>x2" there values are converted to ints.  Thus the type of "x1 + x2" is
>an int and it is *this* that is being converted to a short during the
>assignment to result.
>The original poster was mostly right in the last sentence -- the values
>of short variables in an expression are convert to int if an int can
>hold all possible values, otherwise converted to an unsigned int.  It is
>neither the arguments nor the parameters that are being converted.

     To me, this means that many arithmetic operators can not be done
on short variables without conversion if int is bigger than short.  Is
this what you meant?

     To elaborate, addition could result in a short overflow, but not
int if int is bigger, so it'll be converted.  Similar statements can
be made for subtraction, multiplication, division, and probably
others.

Quote:
>-michael j zehr

Sincerely,

Gene Wirchenko

C Pronunciation Guide:
     y=x++;     "wye equals ex plus plus semicolon"
     x=x++;     "ex equals ex doublecross semicolon"



Wed, 05 Aug 1998 03:00:00 GMT  
 Integral promotion.

Quote:
> > short test(short x1, short x2) {
> >  short result;
> >  result = x1 + x2;

> The addition operator "+" converts your short operands to ints.

No, just using their values does that.  The operator + never sees
operands narrower than int.  In the statement
        x1;
the short is converted to int before being discarded.
--

SoftQuad Inc., Toronto  |                                      --Steve Summit

My text in this article is in the public domain.



Wed, 05 Aug 1998 03:00:00 GMT  
 Integral promotion.

Quote:
> > Hence implementation-defined behavior occurs.

> Thus, the implementation has to say exactly how it handles this.
> There is still some question as to whether the implementation can
> define it as an overflow resulting in program termination, is there
> not?

Nope.  I requote:

*  From 3.10/1.6 (emphasis added):

#  Implementation-defined behavior -- behavior, for a CORRECT program
#  construct and CORRECT data, that depends on the characteristics of
#  the implementation and that each implementation shall document.

If the construct and data are correct, then it can't be correct to cause
program termination.
--

SoftQuad Inc., Toronto                      -- Oliver Wendell Holmes

My text in this article is in the public domain.



Wed, 05 Aug 1998 03:00:00 GMT  
 
 [ 41 post ]  Go to page: [1] [2] [3]

 Relevant Pages 

1. Integral promotion problem

2. integral promotions and char

3. Unsigned arithmetics and integral promotion

4. "integral promotions" and unary arithmetic operators

5. Integral promotion problem

6. Question on integral promotions in ANSI C

7. integral constant suffixes vs. casts

8. constant integral expression

9. Expected Integral Type?

10. A hard integral!

11. Integrals & C, functions

12. integrals in C?

 

 
Powered by phpBB® Forum Software