Welcome to the Memorial Day edition of the A-Z series! As I flipped through the index of Pro C# 2008 and the .NET 3.5 Platform, I happened upon the unchecked keyword - one of those things I remember seeing once or twice, but couldn’t really recall what it did or how it worked. As you might expect, there’s a checked keyword too.
unchecked and its positive counterpart come into play when dealing with integer arithmetic and overflow conditions. Recall that the range for an Int16 variable is ‑32,768 to 32,767, so what do you suppose happens with the following code?
Here’s the result, courtesy of 2’s complement; essentially, we’ve ‘wrapped around’ and are now in negative number territory. There were no errors, reported though, and that’s because this is an unchecked operation by default.
The compiler is smart enough to catch a lot of cases of potential conversion issues, like the following:
Subtle difference, huh? It’s essentially the same statement; however, the type promotion rules for the binary operator + differ just enough from the rules for the compound assigment += to result in this behavior. The good news here is that it makes it harder to unwittingly introduce these types of errors: most of the time the compiler will warn you that an explicit cast is required, even if you try to do something to ‘trick’ it, like this:
You do have the option though to use an explicit cast (and take responsibility for the consequences), and so the following code results in the same erroneous output that I started the post off with:
If you’re really concerned about these types of errors impacting your application, you can use the checked keyword/method, in which case an OverflowException is thrown if there is numeric overflow (which, of course, you’d then be catching to handle a bit more gracefully than this):
By the way, another way to write the checked logic is as follows:
It should be clear by now that by default your code is executing in an unchecked mode. That may seem more dangerous, but given the warnings you get about casting when writing your code, there shouldn’t be too much of an opportunity for surprises. It’s also expensive to make these checks at runtime, so rather than make everyone pay a performance penalty, the default is to let the overflow go undetected at runtime.
But what if you’d still prefer to err on the side of caution, or perhaps you’re working with less-than-robust 3rd party code that you can’t fix at the moment? If you click the Advanced button on the Build tab of your project, you can turn on the automatic detection of overflow and underflow:
… and now the original example throws an exception too.
We’re now erring on the side of caution, but what if there’s now code that we know will cause an overflow/underflow, but we don’t care? Now that I’ve turned it on everywhere, how do I turn it off? As you might expect, that’s where unchecked comes in. To let my original code succeed in spite of the Build property being changed, I can change my code to the following, and it ‘works’ again.
It turns out you can nest the checked and unchecked sections too, which promises to add up to a maintenance nightmare, but it’s nice to know you can do it.