|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
IntroductionIn this article, I thoroughly explore the extremely useful Being able to control overflow checking is one of the many ways that C# improves on C/C++ (and other languages). In theory, C/C++ compilers can do overflow checking for signed integer arithmetic, but the behavior is "implementation defined" according to the C standard. All compilers that I am aware of take the easy way out and ignore overflow conditions - as long as they document the behavior they are considered to be standard conforming. (However, if overflow can occur, you should always use unsigned integer types in C/C++, which are explicitly defined to have unchecked behavior on overflow.) Most of the time, overflow does not occur, but you sometimes want to check for overflows in case your code has bugs. However, where C# is really useful is when you are expecting a possible overflow. I will discuss all situations in the next sections. Overflow Not ExpectedOften overflow is unimportant since it will not occur. In most code, integer variables take on a very small range of small values. I guess this is why most C/C++ compilers ignore the possibility of overflow. Of course, even if you don't expect an overflow condition, it may still occur as a result of a bug. For example, it is easy in C to create an infinite loop by attempting to decrement an unsigned integer below zero. In C#, this would generate an overflow exception if overflow checking was on. In that case, why not always turn overflow checking on when using C#? Well, there is a performance penalty associated with overflow checking. You may not want to slow down your code with overflow checking if you are sure that overflow can never occur. My recommendation is to never use Note that Visual Studio does not turn on overflow checking by default in either release or debug builds. You need to turn on the Check for Arithmetic Overflow setting in the Build Properties for the project - but make sure you have the Debug configuration selected when you do this. Overflow ExpectedThere are two situations where overflow is expected:
We will look at the first situation now, and the second situation in the next section. Many algorithms rely on overflow being ignored. Examples include checksums, and many random number and encryption algorithms. In other words, they rely on arithmetic being performed modulus 2^32 (for 32 bit integers), where any high bits generated are simply discarded. I once had to translate a PRNG (pseudo random number generator) from C to Pascal. Unfortunately, Pascal always does overflow checking. (I could find no way to turn it off with the compiler I was using.) What was about three lines of code in C expanded to about 2 pages of Pascal code. The extra code was simply to avoid causing an overflow. (Even then, I was not certain the Pascal code would handle all conditions, but I knew the 3 lines of C code would work just by glancing at them.) Many C/C++ programmers will not realize, at first, how useful the public override int GetHashCode()
{
return unchecked(name.GetHashCode() + address.GetHashCode());
}
OverFlow CaughtThe second situation, mentioned above, is where you want to detect (not ignore) overflow. It often occurs where the integer values being used are entered or somehow depend on user input. For example, I encountered this situation when I added a calculator to my hex editor (see http://www.hexedit.com). The calculator needed to tell the user when it has performed an operation that caused an overflow. Unfortunately, the code was in C++ and the compiler provided no support for overflow checking. To detect overflows, the code had to examine the operand(s) for each of the operations and try to determine if an overflow was going to happen. The code to do this is not trivial and increases the chances of new bugs being introduced. In fact, the only known bug that has ever caused HexEdit to crash was due to a divide by zero (only when the user attempted to multiply by zero) in code that was trying to detect when a multiplication in the calculator would cause an overflow! This is the sort of situation where the C# Traps For the UnwaryBy now, you may realize that I like the control C# gives over overflow checking. However, there are a few vagaries that you should be aware of. First, it only works for integer arithmetic. Many may expect it to work for floats, decimals etc., but it doesn't. In fact, overflow in floating point numbers ( Another thing to watch is that, even for integers, the As an aside, 0/0 (zero divided by zero) for integers does not cause an error (at least on my machine), but gives a result of zero. According to the C# documentation, it should throw a Conversions between numeric types, where the value to be converted overflows the destination type, can also be Another discrepancy is that overflow checking works for simple arithmetic operations (addition, subtraction, and multiplication), but no overflow checking is performed on left shift operations. For example: uint a = uint.MaxValue;
uint b = checked(a << 1);
uint c = checked(a * 2);
Since a shift is effectively multiplication by a power of 2, you might expect the above ( WarningAn even bigger trap is that the Note that For example: int square(int i)
{
return i * i;
}
void f()
{
checked
{
int i = square(1000000);
}
}
The code in Note that you can inspect the compiled code to see how it changes by looking at the IL code using ILDASM. There are two variations of the relevant commands, without and with overflow checking. For example, the multiply commands are called SummaryIn summary, the C# control of overflow handling is extremely useful where there is possibility of overflow. My rules of thumb for its use are:
Remember that
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||