9

Possible Duplicate:
C integer overflow behaviour when assigning to larger-width integers

I haven't found a clear answer on this in my googling. Say you have two expressions:

int16_t a16 = 100;
int16_t b16 = 2000;
int16_t result16 = (a16 * b16) / a16;

int8_t a8 = 100;
int8_t b8 = 20;
int8_t result8 = (a8* b8) / a8;

When evaluation the expressions (a16 * b16) / a16 and (a8 * b8) / a8, are they always promoted to int during the evaluation and then the final result is converted back to the desired type (int16_t or int8_t) just before the assignment, or is this integer promotion entirely optional? Is integer promotion while evaluating an integer expression always done, or is it just simply allowed?

If it's always done, then I can expect the two operations to not overflow (assuming int is 32-bits). If it's only allowed to be done (and not required), then the operations may overflow. I'd like to know the behavior better.

Community
  • 1
  • 1
Cornstalks
  • 37,137
  • 18
  • 79
  • 144

3 Answers3

6
int16_t result16 = (a16 * b16) / a16;
int8_t result8 = (a8* b8) / a8;

These declarations are the same as:

int16_t result16 = (int16_t) ((int) a16 * (int) b16) / (int) a16);
int8_t result8 = (int8_t) ((int) a8 * (int) b8) / (int) a8);

The integer promotions are required by a conforming implementation. Some embedded compilers by default do not perform integer promotions to enhance code density (example: MPLAB C18 compiler) but these compilers usually also have an ANSI mode to be conforming.

Now for C the behavior is described in terms of an abstract machine in which the issues of optimization are irrelevant. If the compiler can achieve the same observable behavior for the program without performing an integer promotion, it is free not to do it.

Assuming your int is 32-bit, you are right, this expression: (a16 * b16) / a16 cannot overflow.

ouah
  • 142,963
  • 15
  • 272
  • 331
4

First, we have integer promotions, 6.3.1.1/2. Footnote 58 says:

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.

Second, we have the usual arithmetic conversions (6.3.1.8):

[T]he integer promotions are performed on both operands. Then the following rules are applied to the promoted operands:

  • If both operands have the same type, then no further conversion is needed.

Finally, we have the operator. For example, multiplication says (6.5.5):

The usual arithmetic conversions are performed on the operands.

Thus, in the expression a8 * b8, both operands are promoted to int by the integer promotions, then "no further conversion is needed", and so the result of the expression has type int as well.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • Where are you getting a promotion to an `int` from? They are both `in16_t`. – GManNickG Oct 09 '12 at 20:47
  • @GManNickG: Depending on what `int16_t` is, its integer promotion according to 6.3.1.1/2 is `int` (provided it has lower conversion rank). True, this isn't the case when `int16_t` is a type alias for `long int`, but I cut that corner. – Kerrek SB Oct 09 '12 at 20:50
  • 2
    @GManNickG: The standard says that `int16_t` is promoted to `int` if it fits in the range of an `int`. – Dietrich Epp Oct 09 '12 at 20:50
  • 1
    @KerrekSB `int16_t` _cannot_ be a type alias for `long` (in a conforming implementation), the latter must have at least 32 bits, the former is required to have exactly 16 (no padding bits). – Daniel Fischer Oct 09 '12 at 20:52
  • @DanielFischer: Yeah, good point :-) – Kerrek SB Oct 09 '12 at 20:53
  • Wow, I have no idea how I skipped reading that sentence each time. Sorry for the confusion. – GManNickG Oct 09 '12 at 20:53
2

It is not necessary to perform the integer promotions, if the result is exactly the same without them as it would be with the integer promotions (that's an instance of the as-if rule, the implementation may do things anyway it wants, if it is indistinguishable from the way the standard prescribes).

The specification of the arithmetic operators (6.5.5, 6.5.6) says that the integer promotions are performed on the operands, so you can rely on "as if".

You cannot be absolutely sure that the int16_t operation doesn't overflow, however, since int itself may be only 16 bits.

Daniel Fischer
  • 181,706
  • 17
  • 308
  • 431
  • Sorry, I've clarified assuming `int` is 32-bits. So you're saying that integer promotion is required if it might change the result, but not required if it wouldn't change the result? – Cornstalks Oct 09 '12 at 20:43
  • 2
    For the abstract machine, the integer promotions are required. If the implementation can achieve the same result that the abstract machine would produce without promoting to `int/unsigned int`, e.g. with a native 16-bit type with two's complement and wrap-around behaviour, and the conversion `int -> int16_t` is reduction modulo 2^16, then it need not actually convert to `int` for the computation. – Daniel Fischer Oct 09 '12 at 20:50
  • @DanielFischer: It's also worth noting that even in cases where integral promotions could not affect any *defined* behavior, the standard rather annoyingly allows unwanted integral promotions to turn what would be defined behavior into Undefined Behavior. – supercat May 29 '15 at 00:02