Problem with multiplication of signed chars

2019-09-02 11:26发布

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;

4条回答
\"骚年 ilove
2楼-- · 2019-09-02 11:57

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.

查看更多
smile是对你的礼貌
3楼-- · 2019-09-02 12:02

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.

查看更多
再贱就再见
4楼-- · 2019-09-02 12:15

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.

查看更多
【Aperson】
5楼-- · 2019-09-02 12:17

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.

查看更多
登录 后发表回答