views:

169

answers:

4

Today I found the following:

#include <stdio.h>

int main(){
char x = 255;
int z = ((int)x)*2;

printf("%d\n", z); //prints -2

return 0;

}

So basically I'm getting an overflow because the size limit is determined by the operands on the right side of the = sign??

Why doesn't casting it to int before multiplying work?

In this case I'm using a char and int, but if I use "long" and "long long int" (c99), then I get similar behaviour. Is it generally advised against doing arithmetic with operands of different sizes?

+4  A: 

No, you are not getting an overflow on the second line (multiplication). The problem is your compiler is using signed char by default and 255 overflows and will mean -1. Basically, you are initializing variable x with the value of -1. Casting -1 to int will result in -1 (signed operands will get sign-extended in upcasts whereas unsigned operands will get zero-extended).

You can force the char to be unsigned by adding the unsigned prefix:

unsigned char x = 255;
Mehrdad Afshari
+4  A: 

It appears that char is signed on your platform. So the char x = 255 is effectively the same as char x = -1. The cast to int doesn't matter.

Try changing that to:

unsigned char x = 255;
R Samuel Klatchko
+11  A: 

char can be either signed or unsigned, depending on your compiler.

In your case, it appears to be signed, and 255 is outside the range it can represent (likely, it can only represent numbers from -128 to 127).

So the problem occurs when you assign 255 to your char variable - this results in an implementation-defined value, which in your case, appears to be -1.

When you multiply -1 by 2, you get -2. No mystery there. The cast to (int) does nothing - types narrower than int are always promoted to int or unsigned int before any calculations are done with them.

caf
+3  A: 

The other answers nicely explain how your example "works", so I will not explain that again.

However, let me observe that if what you want to use is an "unsigned 8 bit integer", just use <stdint.h>'s uint8_t already (and its 16, 32, 64bit companions) and keep away from all the chars, shorts and ints in this world.

ndim
#include <stdint.h> for these types.
slartibartfast