Understanding Arithmetic Overflow And How Checked And Unchecked Primitive Type Operations Works In C#

I will start this blog by explaining arithmetic overflow.

What is arithmetic overflow?

I will try to explain this concept by using an example.

For example, we have a byte variable i.e., it can hold a value from 0 to 255. If we try to assign the value greater than 255, it will get overflowed.

Example
  1. byte a = 160;  
  2. byte b = 100;  
  3. byte c = (byte)(a+b); 
As per arithmetic operations, the above example should return 260, but byte cannot hold a value greater than 255. Thus, the above operation will return a value of four.

Why four?

The binary value for 260 is 100000100 (9 bits) but byte can hold a max of 255 (i.e max 8 bits) so the left most digit will get truncated and the value will be 00000100 which is equivalent to 4 in decimal form.

Arithmetic overflow can cause unexpected results and can break your application. In the above example, the expected result is 260 but the actual result is 4 which is unexpected.

From the above example, it can be easily concluded that we must select the data type based on what can be the maximum value for that variable.

How Are Arithmetic Overflows Handled in C#?

With the default setting, C# compiler will not throw an exception if arithmetic overflow happens.

Example
  1. class Program  
  2. {  
  3.    static void Main(string[] args)  
  4.    {  
  5.       byte a = 160;  
  6.       byte b = 100;  
  7.       byte c = ((byte)(a+b));  
  8.    }  

The above program will not throw an exception and work fine because C# compiler is configured in that way. We can change/configure compiler settings to throw an exception whenever overflow happens.
 
For every arithmetic operation, there are two overload methods.

Examples:

For Addition 
  • add - will not throw an exception if overflow happens
  • add.ovf- will throw an exception if overflow happens
For subtraction
  • sub - will not throw an exception if overflow happens
  • sub.ovf- will throw an exception if overflow happens
These methods get called under the hood by compiler, but then the question arises how to call specific versions for arithmetic operations.

And the short answer to this is using the checked and unchecked keywords.

If we want the code to throw an exception when arithmetic overflow happens we need to use checked keyword.

Example
  1. class Program  
  2. {  
  3.    tatic void Main(string[] args)  
  4.    {  
  5.       byte a = 160;  
  6.       byte b = 100;  
  7.       byte c = checked((byte)(a+b));  
  8.    }  

Above program will throw an exception as,
[System.OverflowException] {"Arithmetic operation resulted in an overflow."}

With default settings there is no need to use unchecked keyword but if we set "check for arithmetic overflow/underflow" to true in build setting then the below code will throw an overflow exception:
  1. class Program  
  2. {  
  3.    static void Main(string[] args)  
  4.    {  
  5.       byte a = 160;  
  6.       byte b = 100;  
  7.       byte c = (byte)(a+b);  
  8.    }  

The above program will throw an exception as,
[System.OverflowException] {"Arithmetic operation resulted in an overflow."}

In such cases if you want particular operations to ignore arithmetic overflow we can use unchecked keyword as,
  1. class Program  
  2. {  
  3.    static void Main(string[] args)  
  4.    {  
  5.       byte a = 160;  
  6.       byte b = 100;  
  7.       byte c = unchecked((byte)(a+b));  
  8.    }  
  9. }  
Note
Enabling "check for arithmetic overflow/underflow" to true in build setting can cause a performance issue as in every operation it will check for arithmetic overflow/underflow