If you print a negative integer using hex you may be surprised at the result. The binary representation of negative integers in the computer is not at all obvious. Almost all computers now use "2's complement" representation of negative numbers, which is described here.
You can declare a variable to be unsigned or signed. The default is signed. Thus if you declare int x; x will be a signed int. If you declare unsigned int y; then y is an unsigned int. An unsigned int is treated as positive and all the bits may be used. For example if I declare unsigned char m; then m will have eight binary digits, and can have the value 11111111, which is 255.
If you have a signed number with n binary digits, then positive numbers are restricted to be no larger than 2^(n-1)-1. (By 2^n, I mean 2 to the power n.) If x is a positive integer, then x is represented by its ordinary binary representation, and -x is represented by 2^n - x. It is also assumed that if you add two numbers and there is a carry out of the nth place, the carry is lost, and that is the case with all computers that I know about. If you add x and -x, in fact you are adding x and 2^n - x, and the result is 2^n, which is a carry out of the nth place, and is lost, so the result is zero, as it should be.
If x is a positive number, then the first binary digit must be zero, because x<2^(n-1). Then 2^n-x will be greater or equal to 2^(n-1), so the first binary digit must be 1. Thus you can consider the first binary digit to be the sign, and it is 0 for positive numbers and 1 for negative numbers. Here are a few examples using n = 8 to illustrate these ideas:
1 is represented as 00000001. Then -1 is represented as 2^8-1 = 11111111. If you add these as binary numbers, you get 100000000, but this is 9 binary digits. The left-most digit is simply lost, so the answer given by the adder is 00000000. 2 is represented by 00000010, and -2 is 11111110, and again their sum is 00000000. 10 (ten) is 00001010, and so -10 is 11110110, and again their sum is zero. Note that the largest possible value of a signed char variable is 01111111, which is 127.
Now assume signed char n; int k; If you write n = k;, the rightmost eight bits of k are copied into n. If you write k = n; and if n is positive (i. e. its leftmost bit is 0) then the 8 bits of n are copied into the rightmost bits of k and the rest of the bits of k are set to zero. If on the other hand, the first bit of n is 1, then n appears to be negative. Then n is copied into the rightmost 8 bits of k and the rest of k is set to 1's. That will make k have the same numeric value as n, considered as a 2's complement binary integer. You can declare unsigned char n;, then when n is copied to k, it is copied to the rightmost 8 bits of k and the rest of k is always filled with 0's. If you simply declare char n;, then some compilers assume that n is signed and some assume that n is unsigned. If it matters, you should declare signed or unsigned, whichever you want. If n represents an ascii character, then it is positive, because all of the ascii codes are 7 bits long, and the eighth bit, the leftmost one, is zero for all of them. Thus with ascii characters, it really doesn't matter whether n is declared signed or unsigned.
You can experiment. Here is a program that illustrates some of these ideas: (The x format assumes that the variable is an integer. When I tell it to print b using %x format, it converts b to an int first, and the result will have the 8 bits of b with 24 leading 1's in front of them. printf will omit leading zeros, but it will not omit leading non-zero bits, so it prints them all.)
#include <stdio.h>
signed char a = 10, b;
unsigned char e;
int c, d;
int main()
{
b = -a;
c = a;
d = b;
e = b;
printf("a = %d (%02x)\n", a, a);
printf("b = %d (%02x) e = %02x\n", b, b, e);
printf("c = %d (%08x)\n", c, c);
printf("d = %d (%08x)\n", d, d);
return 0;
}
Results:
a = 10 (0a)
b = -10 (fffffff6) e = f6
c = 10 (0000000a)
d = -10 (fffffff6)