Overflow, checked and unchecked

The CLR supports both unchecked and checked integer arithmetics. This post explains how this is exposed in the C# language.

As default, C# does integer arithmetics in a unchecked context. In a unchecked context division by zero throws a exception, whereas overflow does not. Overflow happens when the range of a type is exceeded, e.g. by adding to the byte b, so that result exceeds the range of 0-255. When this happens, the CLR truncates the result, and simply count over from zero: 254, 255, 0, 1, 2 … Hence the following statement will not throw an exception:

for (int i = 0; i < 256; i++)
{
    b++;
}

Checked context

But the CLR actually supports integer arithmetics with overflow checking. You can mark a portion of your code as checked, or use the /checked compiler option to make the whole code compile to in a checked context, causing the following code to throw an OverflowException:

checked
{
    for (int i = 0; i < 256; i++)
    {
        b++;
    }
}

But the overflow checking comes with a performance penalty – actual code like the above (when not overflowing) runs about 3.5 times faster in a unchecked context than in a checked. As an alternative, you can check for overflow youself, given that you know the precise circumstances under which a overflow will happen: 

for (int i = 0; i < 255; i++)
{
    if (b < 255) b++;
}

This check runs a bit faster than the all encompassing CLR check, and reduces the performance penalty to about 2.5.

3 responses to “Overflow, checked and unchecked”

  1. chunkit Avatar
    chunkit

    The third code should be i < 256 and b < 256.
    Depending on what you want, you may want to throw an exception if !(b < 256).

    I guess the performance penalty for using checked is that it checks both b++ and i++, but I can't be sure unless I look into the msil code (haven't learnt to do that yet). Perhaps a good compiler will optimize away the checking on integral variables that can be determined at compile-time never to cause an OverflowException.

  2. chunkit Avatar
    chunkit

    I made a mistake in my previous comment. b < 255 is correct.

  3. Kristoffer Brinch Kjeldby Avatar

    Hi Chunkit

    Yeps – The check happens before the addition.

    Regarding optimization I suspects that the compile will not replace a checked operation with an unchecked, when it is explicit written in the code even – if the check is redundant. I have not checked this however. I you want to go into the msil code, you can use the MSIL Disassembler (Ildasm.exe).

    Regards Kristoffer