Why You Should Learn CIL
The Common Intermediate Language is the language that your .NET apps compile to.
If you’re a .NET developer, you’ve probably heard of it before but know that there’s no point in learning it since it’s an “implementation detail”.
This article will provide an example which will hopefully convince you that a lack of CIL knowledge can lead to bugs.
The “checked” keyword
C#'s checked throws an OverflowException if the artithmetic operation results in an overflow.
Example 1
In this example, an overflow happens and you’ll get an OverflowException because 1 is added to a byte that is already at its maximum possible value.
The bug
Now you know what checked does, look at example 2.
Example 2:
At first glance, this looks like it should do exactly the same thing as example 1, but it doesn’t.
No OverflowException is thrown when you try to add 1 to the byte!
What’s different?
To understand what’s going on here, we need to look at the CIL that gets generated for example 1 with the checked keyword removed.
Example 1 CIL, with checked removed:
Don’t worry too much about what all these lines mean, just have a look at IL_0009: add.
All this does, is add two numbers together, 255 and 1.
Example 1 CIL, with checked:
This is almost exactly the same as the code that gets generated when checked is removed. The only difference is a few more nop instructions, and .ovf after add:
Get David Klempfner’s stories in your inbox
Join Medium for free to get updates from this writer.
IL_000a: add.ovf
This does exactly the same thing as a normal add, but it also throws an OverflowException if there is an overflow.
Conclusion
checked only works for expressions directly inside the checked block.
What about Decimal?
In this example, we’re using unchecked, which assures that an OverflowException will not be thrown.
When this happens, the number wraps around to its smallest value.
(You can change the -checked compiler option to set whether the default should be checked or unchecked).
Example 3:
Will this throw anOverflowException or not?
At first glance, it looks like this will not throw an OverflowException.
And if it was using int or byte instead of decimal, it would indeed not throw an OverflowException.
However, it does throw an OverflowException!
Why?
Here’s the CIL that gets generated.
Notice there are no add or add.ovf instructions like there was with byte.
Instead of the built in CIL add or add.ovf instructions, it uses a method called op_Addition (line 12).
Although decimal is a primitive type in C#, the CLR does not consider it a primitive type and therefore doesn’t have CIL instructions to manipulate it.
Instead, the decimal type has its own methods for addition, subtraction etc. This means the add CIL instruction we saw earlier, is not used for decimal.
Because of this, checked and unchecked have no effect on the decimal type.
Summary
Having a basic understanding of CIL, or at least having enough interest to have a look at what CIL gets generated from your C# code, can provide incredible insight into how things work.
These low level details are not only satisfying to learn/understand, but can help you write better, bug-free code.









