Here are two very simple programs. I would expect to get the same output, but I don't. I can't figure out why. The first outputs 251. The second outputs -5. I can understand why the 251. However, I don't see why the second program gives me a -5.
#include <stdio.h>
int main()
{
unsigned char a;
unsigned char b;
unsigned int c;
a = 0;
b= -5;
c = (a + b);
printf("c hex: %x\n", c);
printf("c dec: %d\n",c);
}
Output:
c hex: fb
c dec: 251
#include <stdio.h>
int main()
{
unsigned char a;
unsigned char b;
unsigned int c;
a = 0;
b= 5;
c = (a - b);
printf("c hex: %x\n", c);
printf("c dec: %d\n",c);
}
Output:
c hex: fffffffb
c dec: -5
There are two separate issues here. The first is the fact that you are getting different hex values for what looks like the same operations. The underlying fact that you are missing is that char
s are promoted to int
s (as are short
s) to do arithmetic. Here is the difference:
a = 0 //0x00
b = -5 //0xfb
c = (int)a + (int)b
Here, a
is extended to 0x00000000
and b
is extended to 0x000000fb
(not sign extended, because it is an unsigned char). Then, the addition is performed, and we get 0x000000fb
.
a = 0 //0x00
b = 5 //0x05
c = (int)a - (int)b
Here, a
is extended to 0x00000000
and b
is extended to 0x00000005
. Then, the subtraction is performed, and we get 0xfffffffb
.
The solution? Stick with char
s or int
s; mixing them can cause things you won't expect.
The second problem is that an unsigned int
is being printed as -5
, clearly a signed value. However, in the string, you told printf
to print its second argument, interpreted as a signed int (that's what "%d"
means). The trick here is that printf
doesn't know what the types of the variables you passed in. It merely interprets them in the way the string tells it to. Here's an example where we tell printf
to print a pointer as an int:
int main()
{
int a = 0;
int *p = &a;
printf("%d\n", p);
}
When I run this program, I get a different value each time, which is the memory location of a
, converted to base 10. You may note that this kind of thing causes a warning. You should read all of the warnings your compiler gives you, and only ignore them if you're completely sure you are doing what you intend to.