2

a + b overflows 255 back to 4 as I would expect, then c / 2 gives 2 as I expect. But then why does the last example not overflow when evaluating the same two steps?

I'm guessing the internal calculation values are stored with more bits, then only truncated down to 8 bit when doing the assignment. In that case where is the limit, it must overflow at some point?

uint8_t a = 250;
uint8_t b = 10;
uint8_t c = (a + b);
uint8_t d = c / 2;
uint8_t e = (a + b) / 2;

std::cout << unsigned(c) << ", " << unsigned(d) << ", " << unsigned(e) << "\n";

4, 2, 130

Harry
  • 11,298
  • 1
  • 29
  • 43
trapper
  • 11,716
  • 7
  • 38
  • 82

4 Answers4

2

It's called integral promotion. The operations themselves are done in your CPUs native integer type, int, which can hold numbers greater than 255. In the a+b case the result must be stored in an uint8_t, and that's where the truncating is done. In the last case first there is a division which is done as an int, and the result can be perfectly stored in an uint8_t.

atturri
  • 1,133
  • 7
  • 13
  • So I would get a different result on different CPUs depending on their native int size? – trapper Apr 11 '16 at 05:50
  • Yes, but `int` must always be able to hold at least 32767, so in this case with 255 you will always get the same result. – atturri Apr 11 '16 at 05:52
  • @trapper Also note, that wrapping on overflow is only defined for *unsigned* integers. Overflowing *signed* integers is undefined behaviour. – Jesper Juhl Apr 11 '16 at 06:01
0

a+b gives value 260 which is not assigned to any uint8_t type so you are good in the last case. Only when you assing any value greater than 255 to uint8_t then there is a overflow.

Gopi
  • 19,784
  • 4
  • 24
  • 36
  • `a+b` is 260 which rolls over to 4. The question is why doesn't this happen with `(a+b)/2` – trapper Apr 11 '16 at 05:49
  • @trapper Yeah edited my answer. `a+b = 260` but 260 is not assigned to any `uin8_t` to be truncated/overflowed to become 4 – Gopi Apr 11 '16 at 05:50
0

In the following (a + b) does not overflow, the compiler recognizes a and b as Integer Types so addition results in an Integer Type, the result of this expression is not restricted by the size of the terms or factors in the expression.

Lets assume the type of a variable like a or b in this case limits the result to only that type. While possible it would be almost impossible to use a language like this. Imagine five variables that when no type consideration is made they sum to 500 ie this..

uint8_t a = 98;
uint8_t b = 99;
uint8_t c = 100;
uint8_t d = 101; 
uint8_t e = 102;

The sum of the above variables == 500. Now... in the following the result of any expression cannot exceed the size of one of the terms...

int incorrect = (a + b + c + d + e);

in this case (a + b + c) == 41 then (41 + d + e) == 244. This is a nonsensical answer.. The alternative that most people recognize ie

(98 + 99 + 100 + 101 + 102) == 500;

This is one reason why type conversion exists.

Intermediate results in expressions should not be restricted by the terms or factors in the expression but by the resultant type ie the lvalue.

Harry
  • 11,298
  • 1
  • 29
  • 43
0

@atturri is correct. here is what happen to your variables in x86 machine language:

REP STOS DWORD PTR ES:[EDI]
MOV BYTE PTR SS:[a],0FA
MOV BYTE PTR SS:[b],0A
MOVZX EAX,BYTE PTR SS:[a] ; promotion to 32bit integer
MOVZX ECX,BYTE PTR SS:[b] ; promotion to 32bit integer
ADD EAX,ECX
MOV BYTE PTR SS:[c],AL ; ; demotion to 8bit integer
MOVZX EAX,BYTE PTR SS:[c]
CDQ
SUB EAX,EDX
SAR EAX,1
MOV BYTE PTR SS:[d],AL
MOVZX EAX,BYTE PTR SS:[a]
MOVZX ECX,BYTE PTR SS:[b]
ADD EAX,ECX
CDQ
SUB EAX,EDX
SAR EAX,1
MOV BYTE PTR SS:[e],AL
Afshin
  • 392
  • 2
  • 11