473,246 Members | 1,360 Online

# integer promotion and arithmetic conversion

Hi,
What is integer promotion? How is it different from
arithmetic conversion?

Regards,
Sarathy

Aug 16 '06 #1
6 13779
sarathy wrote:
Hi,
What is integer promotion? How is it different from
arithmetic conversion?

Regards,
Sarathy
AFAIK, integer promotion refers specifically to integer types
participating in a binary operation (read: sub-expression) where the
types of operands must be identical (+ - * / % | ^ &).
E.g.,
char c;
short s;
unsigned u;
long l;
If I am not mistaken in this wee hour;
u+l means (long)u+l even if sizeof(unsigned)==sizeof(long)
s+u means (unsigned)s+u even if sizeof(unsigned)==sizeof(short)
c+s means (int)c+(int)s
etc.
signed promotion is value-preserving; promotion to an unsigned type
preserves the bit pattern.
Additionally, everything in an expression is promoted to at least int:
c+s means (int)c+(int)s
(I believe, in the old days it was not NECESSARILY true and was
implementation-defined.) E.g., on a typical 32-bit machine
unsigned short s = 0x1000U;
......
s<<4 means ((int)s)<<4, i.e., 0x10000, not a short value.

These rules are made so that C programmers capable of writing robust
arithmetic expressions (or better yet, portable ones) could command big
bucks :)
Aug 16 '06 #2
sarathy schrieb:
Hi,
What is integer promotion? How is it different from
arithmetic conversion?
I just gave a very loose explanation in
<4k************@individual.net>
As this is IMO one of the topics that are presented rather
readable in the standard text, I suggest that you have a look
at "n1124.pdf" (just google for it), section 6.3.
Note that this is the current C99 standard plus technical
corrigenda -- C90 did behave a little bit different when it
came to the usual arithmetic conversions for operations involving
floating point operands and had no long long type.

Cheers
Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.
Aug 16 '06 #3
Ark wrote:
>
sarathy wrote:
Hi,
What is integer promotion? How is it different from
arithmetic conversion?

Regards,
Sarathy
AFAIK, integer promotion refers specifically to integer types
participating in a binary operation (read: sub-expression) where the
types of operands must be identical (+ - * / % | ^ &).
E.g.,
char c;
short s;
unsigned u;
long l;
If I am not mistaken in this wee hour;
u+l means (long)u+l even if sizeof(unsigned)==sizeof(long)
That's not what integer promotion is.
Integer promotion can only result in an expression
of either type int or type unsigned.

sizeof(c + c) == sizeof(u)

--
pete
Aug 17 '06 #4
pete wrote:
Ark wrote:
>sarathy wrote:
>>Hi,
What is integer promotion? How is it different from
arithmetic conversion?

Regards,
Sarathy
AFAIK, integer promotion refers specifically to integer types
participating in a binary operation (read: sub-expression) where the
types of operands must be identical (+ - * / % | ^ &).
E.g.,
char c;
short s;
unsigned u;
long l;
If I am not mistaken in this wee hour;
u+l means (long)u+l even if sizeof(unsigned)==sizeof(long)
That's not what integer promotion is.
Integer promotion can only result in an expression
of either type int or type unsigned.

sizeof(c + c) == sizeof(u)
You are correct of course:
6.3.1.1
The following may be used in an expression wherever an int or unsigned
int may be used:
— An object or expression with an integer type whose integer conversion
rank is less than or equal to the rank of int and unsigned int.
— A bit-field of type _Bool, int, signed int, or unsigned int.
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. These are called the
integer promotions.48) All other types are unchanged by the integer
promotions.

48) The integer promotions are applied only: as part of the usual
arithmetic conversions, to certain
argument expressions, to the operands of the unary +, -, and ~
operators, and to both operands of the
shift operators, as specified by their respective subclauses.
Aug 17 '06 #5
In article <DI******************************@comcast.com>
Ark <ak*****@macroexpressions.comwrote:
>char c;
short s;
unsigned u;
long l;
If I am not mistaken in this wee hour;
u+l means (long)u+l even if sizeof(unsigned)==sizeof(long)
s+u means (unsigned)s+u even if sizeof(unsigned)==sizeof(short)
c+s means (int)c+(int)s
Alas, you are mistaken. The ANSI/ISO rules are terribly complicated
by depending on the relative values of the corresponding MAXes.

Consider the "u+l" case for a moment. Suppose we are on a typical
32-bit machine, with 32-bit int and 32-bit long, and hence both
INT_MAX and LONG_MAX are 2147483647 while UINT_MAX is 4294967295.

The ANSI "value-preserving" rule says that widening a narrower
signed type produces a new, wider signed type if and only if the
relative *_MAX is not exceeded. Otherwise, it produces a new,
wider unsigned type.

Since UINT_MAX exceeds LONG_MAX, widen(u) produces unsigned long,
instead of signed long. We then have (unsigned long) + (signed long);
the second "signed" long is converted to "unsigned", and the addition
is done with unsigned arithmetic -- where overflow is discarded --
and the result has type "unsigned long".

If LONG_MAX is greater than UINT_MAX, however, widen(u) produces
signed long. We then have (signed long)+(signed long); the addition
is done in signed arithmetic (overflow giving undefined behavior)
and the result has type "signed long". This is the case on a
typical 64-bit machine (32-bit int, 64-bit long).

>signed promotion is value-preserving;
This is correct: it preserves the value if possible (if the new
wider type has a lower *_MAX, we hit a snag; but this case is either
completely ruled out by the Standard, or else at least never seems
to occur in practice; I am not sure which). (C89 and C99 have
somewhat different wording, in part because C99 now has "long long"
as well.)
>promotion to an unsigned type preserves the bit pattern.
This is only true for two's complement systems. On a Univac, you
get some interesting code.

[test code]
#include <stdio.h>

long l;
unsigned u;

void f0(void) { if (u + l 0) puts("u + l is unsigned"); }
void f1(void) { if ((long)u + l 0) puts("(long)u + l is unsigned"); }
void f2(void) { if (u + (unsigned)l 0) puts("u + (unsigned)l is unsigned"); }

int main(void) {
u = -1U, l = -1L; /* -1L + -1L = -2L */
f0();
f1();
f2();
return 0;
}

--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
Reading email is like searching for food in the garbage, thanks to spammers.
Aug 20 '06 #6

Chris Torek wrote:
In article <DI******************************@comcast.com>
Ark <ak*****@macroexpressions.comwrote:
char c;
short s;
unsigned u;
long l;
If I am not mistaken in this wee hour;
u+l means (long)u+l even if sizeof(unsigned)==sizeof(long)
s+u means (unsigned)s+u even if sizeof(unsigned)==sizeof(short)
c+s means (int)c+(int)s

Alas, you are mistaken. The ANSI/ISO rules are terribly complicated
by depending on the relative values of the corresponding MAXes.

Consider the "u+l" case for a moment. Suppose we are on a typical
32-bit machine, with 32-bit int and 32-bit long, and hence both
INT_MAX and LONG_MAX are 2147483647 while UINT_MAX is 4294967295.

The ANSI "value-preserving" rule says that widening a narrower
signed type produces a new, wider signed type if and only if the
relative *_MAX is not exceeded. Otherwise, it produces a new,
wider unsigned type.

Since UINT_MAX exceeds LONG_MAX, widen(u) produces unsigned long,
instead of signed long. We then have (unsigned long) + (signed long);
the second "signed" long is converted to "unsigned", and the addition
is done with unsigned arithmetic -- where overflow is discarded --
and the result has type "unsigned long".

If LONG_MAX is greater than UINT_MAX, however, widen(u) produces
signed long. We then have (signed long)+(signed long); the addition
is done in signed arithmetic (overflow giving undefined behavior)
and the result has type "signed long". This is the case on a
typical 64-bit machine (32-bit int, 64-bit long).
This explanation is quite good, but I have a quibble.
For promotions, there is a notion of widening. For
binary operators though, both operand types participate
in finding a common real type and both operand values
are converted to that type. It isn't that we "widen"
one type and convert the other - both operands are
simply converted (and indeed no widening may take
place even when the conversion ranks are different).

Don't get me wrong, I like the explanation; I just
think it could be better if couched in language
more closely parallel to how language in the Standard
expresses it.

Aug 24 '06 #7

This thread has been closed and replies have been disabled. Please start a new discussion.