
In C every number has a type, and the type says how many bytes it lives in, which decides how big it can get. On this machine there are three kinds and none of them holds a fraction, and if you know that before you start you will be spared a whole family of puzzling results - including one that is this compiler's own.
intAn int is the ordinary whole number. On this compiler it is two bytes, sixteen bits, which gives it 65,536 different values, and they are spread from -32,768 to 32,767. That is the whole range. There is no bigger whole number on this disc: long is accepted by the compiler and is the same two bytes.
What happens at the ends is the first thing to see:
32767 + 1 = -32768
-32768 - 1 = 32767
Nothing stops, nothing warns. The bits roll over like a car's odometer, and the number after the biggest is the smallest. The manual says it in one line: "integer overflows are ignored". Every calculation in this course has to stay inside those limits, and the ones that do not give answers that are wrong without looking wrong: 200 * 200 is -25536, and 30000 + 30000 is -5536.
unsignedAn unsigned is the same two bytes read differently: 0 to 65,535, no negatives. It rolls over the same way - 65535 + 1 = 0 - and its use is for things that are never negative and might pass 32,767: addresses, sizes, counts of bytes. %u prints one; %d of the same bits prints the signed reading, which is how 200 * 200 comes out as 40000 with %u and -25536 with %d. Same bits, two ways of reading them.
charA char is one byte, and it is the type for a character - 'G' is the number 71 in a char - but it is a number all the same, and on this compiler it is unsigned: 0 to 255. That is the one to remember if you know C from elsewhere, where a char is usually signed. Put 200 in a char and read it back and you get 200; put -1 in and you get 255; put 300 in and you get 44, because only the bottom byte fits. Add 1 to 255 and you get 0.
It matters when you use a char to hold something that is not a character and expect it to go negative. It will not. Use an int.
Whole numbers divide into whole numbers: / gives the quotient with the fraction dropped, and % gives the remainder. So 7 / 2 is 3 and 7 % 2 is 1. With a negative number the quotient is rounded toward zero: -7 / 2 is -3, and the remainder keeps the sign of the number being divided, -7 % 2 is -1.
Dropping the fraction happens at each step, so 100 / 3 * 3 is 99, not 100. And dividing by zero is not caught: 10 / z with z at 0 printed 15 and the program went on. The manual says so - "attempts to divide by zero" are ignored - and the answer is whatever the arithmetic routine happens to leave, so a strange result is worth a look at the divisor.
A number written as digits is decimal. 0x1F is hexadecimal - 31 - and a number with a leading zero is octal: 017 is 15, not 17. That leading zero catches everyone once.
sizeof tells you the size of a type in bytes - sizeof(int) is 2, sizeof(char) is 1 - and on this compiler it takes the name of a type, never a variable.
#include STDIO.H
main()
{
int big, small;
unsigned u;
char c;
big = 32767;
printf("%d + 1 = %d\n", big, big + 1);
small = -32768;
printf("%d - 1 = %d\n", small, small - 1);
u = 65535;
printf("%u + 1 = %u\n", u, u + 1);
c = 200;
printf("char 200 is %d\n", c);
c = 255;
c = c + 1;
printf("char 255 + 1 is %d\n", c);
printf("%d %d %d %d\n", 7 / 2, 7 % 2, -7 / 2, -7 % 2);
printf("%d %d\n", 0x1F, 017);
printf("%d\n", sizeof(int) + sizeof(char) * 10);
}
#include ?STDIO.LIB?
The declarations at the top - int big, small; and the rest - give each name its type. S10 is about them; here they are just the four numbers the program uses.
Starting from
Typed as NUM.C; compiled and run.
What you should see
32767 + 1 = -32768
-32768 - 1 = 32767
65535 + 1 = 0
char 200 is 200
char 255 + 1 is 0
3 1 -3 -1
31 15
12
If you know C from elsewhere you are waiting for float and double. Type one and the compiler stops:
ERROR 46 AT LINE 4 IN FILE FLOAT.C
RESTRICTION: Floating Point not implemented
HiSoft's manual says the same, and adds "sorry". So on this disc there are no fractions and nothing past 65,535. Every number in this course is an int, an unsigned or a char, and the game is written that way.
c = 200 to c = -1. What do you predict %d will print, and why?sizeof(unsigned) * sizeof(char). Then try sizeof(u). What does the compiler say to the second?-7 / 2 * 2 + -7 % 2. Does it get back to -7?9.1 Print the number of minutes in a day, and then the number of seconds in a day. Look at the second answer carefully.
9.2 Print 65535 with %d, and -1 with %u.
9.3 Write printf("%d\n", 0100); and predict the output before you run it.
Worked solutions are in Appendix II.
| Symptom | Cause |
|---|---|
| A sum that should be large comes out negative | It passed 32,767 and rolled over. Use unsigned if it never goes negative and stays under 65,536; otherwise there is no type for it here. |
A char that should be negative is a large positive number | A char is unsigned here. Use an int. |
| A number with a leading zero is smaller than you wrote | It was read as octal. |
| A division prints something absurd | The divisor was 0. |
RESTRICTION: Floating Point not implemented | You used float or double. |
need a type name at a sizeof | sizeof wants a type, not a variable. |
int is -32,768 to 32,767 and rolls over; unsigned is 0 to 65,535; char is one unsigned byte, 0 to 255. Division drops the fraction toward zero, and division by zero gives rubbish. 0x is hex and a leading 0 is octal. No float, and long is only an int.
S10, Names - declaring variables, giving them values, where declarations may and may not go, and naming your own types.