-1

I dont understand what is happening when I multiply char variable and and int variable and put the result into a char.

For example:

char p= (98*'b') ;
printf("%d",p);

Why it is -124?

I expected for overflow.

Jabberwocky
  • 48,281
  • 17
  • 65
  • 115
Adam z
  • 1
  • 1
    Welcome to SO. What exactly did you expect? How did you expect this overflow should look like? As you can see, you multiply 2 positive values and get a negative result. That looks fairly close to some overflow. But not during multiplication. Try to add some intermediate step: `int result = 98*'b'; char p = (char)result; printf("%d, %d\n", result, p);` – Gerhardh Apr 18 '23 at 07:39
  • 1
    "I expected overflow". There is: `'b'` is ASCII code `98`, then `98 * 98` is `0x2584` which was then converted to signed 8 bits `0x84` which is decimal `-124`. Note that `char` (a numeric value) is automatically promoted to `int` when passed to `printf`, so that's ok to pass it for `%d` format spec. – Weather Vane Apr 18 '23 at 07:41
  • Oops, the duplicate is wrong. I was distracted by the title stating `char` was multiplied which is not true. There is no type promotion done in the multiplication. You need to be aware that `'b'` is of type `int`, not `char`. That means you multiple 2 `int` values. Only when you assign to a smaller type, the problem happens. – Gerhardh Apr 18 '23 at 07:44
  • @אד זוודה how an out-of-range value is assigned to a **signed** type that is smaller is "implementation defined", and for unsigned types it is well defined by the C standard. Here, it appears that your implementation has truncated the excess bits from the value. – Weather Vane Apr 18 '23 at 07:50

3 Answers3

3

It is because the char is signed. A signed char has a value of -128 to 127.

So, when you get the value 0x2584, the MSB is ignored and you actually get the value 0x84.

Now, 0x84 in binary is:

1000 | 0100 = 0x84

The Most Significant Bit is set, hence it being treated as a negative number.

So, if the Most Significant Bit is set we have:

1000 | 0000 = 0x80 = -128
1000 | 0001 = 0x81 = -127
1000 | 0010 = 0x82 = -126
1000 | 0011 = 0x83 = -125
1000 | 0100 = 0x84 = -124

Which is what you get.

If you are looking for a value of 0x2584 then you need to use a 16 bit datatype as a minimum, which would probably be a regular int on your platform.

If you are looking for the actual value of 0x84 then you need to use an unsigned char datatype. Something like:

unsigned char p= (98*'b') ;
printf("%d",p);
Mike
  • 419
  • 3
  • 7
  • I don't completely agree. The overflow would happen also in the case of `unsigned char` target, as the original result was 9604, and the maximum value for `unsigned char` is also below that (255). It doesn't fit in a `char` either `signed` or `unsigned`, most probably. Also, he had used a `short`, would have sufficed to make the result valid, without overflow (`signed` or `unsigned`) – Luis Colorado Apr 26 '23 at 06:03
  • @LuisColorado - He wanted it to overflow, but to show the value 0x84 as an unsigned value. That will happen with an unsigned char. You are correct that a short would work, but I wasn't sure on his environment and the safe option was an int. – Mike Apr 26 '23 at 06:08
  • well, `short` is warranted to be, at least 16 bits wide, and this means enough to support 9604. Being `signed` or `unsigned`. The `signed` case is special, as the C standard considers all the `signed` overflows as undefined behaviour, what means that anything could happen, even the exception and program interrupt he was probably expecting. – Luis Colorado Apr 26 '23 at 06:34
  • @LuisColorado - Yep, that is why I said he would need a 16 bit variable to see the full value. Trouble is, some systems don't have a 16 bit variable, so a short might not be available. – Mike Apr 26 '23 at 06:41
  • i've never heard of a C system lacking 16 bit integers. – Luis Colorado Apr 26 '23 at 06:51
  • @LuisColorado - My bad - doh, what I meant to say was that some systems don't have a short, as in, they might have an int16 but no "short" type if that makes sense! You and I probably know instantly that a short is likely to be a 16bit value, but others might not. I used the int as pretty much everyone knows what that is. I hope that makes sense :-) – Mike Apr 26 '23 at 08:09
2

What happens "between the lines":

  • (98*'b') the parenthesis adds nothing.
  • Everything in C has a type, including integer constants and character constants. As it happens both 98 and 'b' are of type int.
  • The multiplication is therefore carried out on int and the result is of type int. 9604 decimal or 0x2584 hex.
  • You then attempt to store this inside a char which cannot hold such a large value. Further problematic is that the char type has implementation-defined signedness and could be either signed or unsigned, it is a non-portable type when it comes to storing values. Is char signed or unsigned by default?
  • In case char is unsigned, the conversion is well-defined and you get the value 0x84 hex / 132 dec.
  • In case char is signed, the conversion is implementation-defined. Most mainstream systems with 2's complement will however do the equivalent of just translating 0x84 to a 1 byte 2's complement number. Meaning -124.
  • Passing a char to printf("%d",... is strictly speaking not-well defined since %d means it expects an integer. This happens to work "by accident" since parameters passed to variadic functions undergo an implicit type promotion ("default argument promotions") and in case of char it gets promoted to int. To print signed char integer values reliably, use %hhd.

Best practices:

  • Never use char for anything else but to store characters. AVoid using it for arithmetic, particularly bitwise operations.
  • Instead use the portable byte type uint8_t in stdint.h.
  • Use correct format specifiers to printf.
Lundin
  • 195,001
  • 40
  • 254
  • 396
0

I dont understand what is happening when I multiply char variable and and int variable and put the result into a char. Why it is -124?

Well, you got an overflow. the result of 98 * 'b' (which is also 98 * 98) is 9604 but a char must be a number between (a signed char) -128 and 127. Finally you got it overflowed, being the final result Undefined Behaviour (which can be anything, even the correct result, but not this time) So you got what was unexpected :)

In C, integer arithmetic can overflow without you being notified, because no error, and no exception is fired when it happens. You must be aware of the types you use, and you should be aware that 98^2 doesn't fit as a positive number in the range 0..127 (which is the range of a signed char). So you have experienced an overflow, and the compiler didn't say anything about it, which is the expected Undefined Behaviour.

Upto here, this is what you got from the C standard perspective. The most probable thing that could happen is that you got the shown result after cutting down all the bits of the number that don't fit in a char (9604 mod 256 -> 132, unsigned, and this is the unsigned char representation of two's complement signed char -124, this is, 256 - 124 = 132).

Luis Colorado
  • 10,974
  • 1
  • 16
  • 31
  • There was no overflow in `98 * 'b'` because both `98` and `'b'` are `int` values. – Andrew Henle Apr 19 '23 at 15:42
  • right, the overflow happens on converting the result to a `char`. As I say, the result of the operation is 9604, and that overflows the range of a `signed char`. – Luis Colorado Apr 20 '23 at 15:30