Overflow
The dashboard of an old car has a mechanical odometer: six wheels with digits. After 999999 kilometers the wheels roll over, and the odometer shows 000000 again. It has no seventh digit, and there is nowhere to write a larger number.
The int type works in a similar way. It has a fixed number of digits, so it holds numbers only from int.MinValue to int.MaxValue—you already printed these limits in the theme on types. What happens if you add one to the largest value?
int max = int.MaxValue;
Console.WriteLine(max); // 2147483647
Console.WriteLine(max + 1); // -2147483648
int min = int.MinValue;
Console.WriteLine(min - 1); // 2147483647Let's go through the program line by line:
maxholds the largestintvalue, and the program prints2147483647.max + 1prints not2147483648but-2147483648: the count jumped to the smallest value.min - 1jumps the other way, to the largest value.
Here the odometer picture parts ways with int. After its maximum the odometer shows zero, while int shows its smallest negative number. Half of the int values are negative, and past the top edge the count goes on from the bottom one.
Unchecked by default
When a result does not fit in its type, it is called an overflow. By default C# does not check integer operations for overflow: the extra binary digits are dropped, and the value silently jumps over the edge. There is no error and no exception, and the program goes on computing with a wrong number.
Interviewers like to ask this: what happens when you add one to int.MaxValue? The answer: at run time you get int.MinValue, with no error and no exception.
When the numbers go past two billion, use long: its maximum has 19 digits. But a long overflows in exactly the same way, only much later.
Checking with checked
A silent overflow is dangerous: the program produces a wrong result and shows no sign of it. To make C# check an operation, wrap it in checked(...). An overflow then throws an OverflowException, and the program stops at that line:
int max = int.MaxValue;
Console.WriteLine(checked(max + 1)); // ✗Unhandled exception. System.OverflowException: Arithmetic operation resulted in an overflow.You can also put checked before curly braces: checked { max++; } checks every integer operation inside them.
Overflow at compile time
When an expression consists only of literals and constants such as int.MaxValue, the compiler computes the result before the program runs and notices the overflow itself. This line does not compile:
Console.WriteLine(int.MaxValue + 1); // ✗error CS0220: The operation overflows at compile time in checked modeFor such expressions the check is on by default—that is what the words checked mode in the message say. That is why the examples in this lesson put the maximum into the variable max first: the compiler does not compute a variable's value in advance.
Common mistake
The product of two int values is stored in a long, in the hope that the bigger type will hold the result:
int million = 1000000;
long wrong = million * million; // ✗
Console.WriteLine(wrong); // -727379968
long right = (long)million * million;
Console.WriteLine(right); // 1000000000000The compiler sees no error, and the program prints -727379968. Both operands of million * million are int, so the multiplication runs in int too: the result overflows before it reaches the long. Cast one of the operands to long: (long)million * million multiplies in long and gives 1000000000000.
Key points
intholds numbers fromint.MinValuetoint.MaxValue; past an edge the value silently jumps to the other edge.checkedturns an overflow into anOverflowException.- When an expression holds only literals and constants, the compiler finds the overflow, and such code does not compile.
- The operands set the type of the result:
int * intoverflows before it reaches along.