0

Discussing this answer I find out that the code bellow prints -1 and 1 in visual studio. Why? In my opinion it should print two 1s despit overflow during multiplication.

signed char c1 = numeric_limits<signed char>::min();
signed char c2 = -1;
cout << c1 * c2 / c1 << endl;
signed char result = c1 * c2;
cout << result / c1 << endl;
Community
  • 1
  • 1
Mihran Hovsepyan
  • 10,810
  • 14
  • 61
  • 111

4 Answers4

4

c1 might have a value like -128, say. In the multiplication, integer promotions will cause both c1 and c2 to be converted to type int before the operation is performed.

c1 * c2 is then going to be a int with value 128 so c1 * c2 / c1 is going to be an int with value -1.

-1 for the first output looks correct to me.

For the second version, typically the assignment of the result of c1 * c2 won't fit into a signed char and will convert to an implementation-defined result, perhaps -128 instead of 128.

CB Bailey
  • 755,051
  • 104
  • 632
  • 656
2

Integer overflow is considered UB. This means that the compiler will consider (c1 * c2 / c1) to be completely equivalent to c2.

You can check this for additional info.

Community
  • 1
  • 1
ruslik
  • 14,714
  • 1
  • 39
  • 40
0

c1 * c2 is an int multiplication (5/9 in the standard). We know that CHAR_BIT is 8 on MSVC and that it uses two's complement representation for signed types, so we know the value: -128 * -1 is 128.

128 / -128 is -1, so that's the first result sorted.

Assigning -CHAR_MIN to a signed char has implementation-defined results (4.7/3), but we know in MSVC the result is -128. Then -128 / -1 is 1, so that's the second result sorted.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
0

The first case, making upscaling to an int explicit:

cout << ((int)c1 * c2 / c1 << endl;

the second case, assigning to an intermediate variable is equivalent to

cout << ((signed char)((int)c1 * c2)) / c1 << endl;

(Implicit casts to int done by the compiler made explicit.)

With two's complement, multiplying the largest negative value of a type by -1 leaves the value unchanged if it is restricted to the same number of bits. So, the second example, c1*c2 == c1. Even though the multiplication is done as an int, it is cast back to the width of a char.

In the first example, the entire calaulation is done as an int, so the operation has more bits to work with, and so the truncation doesn't occur. Here, c1*c2 == (c1*-1) == -c1. Hence the different result.

mdma
  • 56,943
  • 12
  • 94
  • 128
  • The promotion to `int` is redundant, the implementation does this anyway. In this case, in `(signed char)((int)c1 * c2)` there is no overflow of an arithmetic operation, there's an explicit conversion from one integer type to another. This would be implementation-defined, not underfined behavior. – CB Bailey Apr 30 '11 at 10:29