Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

unchecked -keyword in C#

Maybe I'm in the basics, but I'm still studying this C# thing at school. I understand that if I add 1 to max valued Integer, which one is 32 bit, the result will be negative. I read that C# offers checked and unchecked keywords for handling overflows. Checked keyword is something, I've found useful, but how about unchecked keyword? I really can't find not much useful use for unchecked -keyworded block. Is there any? How does the next two approaches differs from each others?

using System; using System.Collections.Generic; using System.Linq; using System.Text;  namespace Practice_6 {     class Program     {         static void Main(string[] args)         {             int value = Int32.MaxValue;             value++;             //Approach 1 to make a decision             if (value > Int32.MaxValue) {                 //Do something             }             value = Int32.MaxValue;             //Approach 2 to make a decision             unchecked {                 value++;                 //Do something             }             //What's the difference between these two approaches to handle overflow?     } } 
like image 909
Jere_Sumell Avatar asked Sep 11 '14 03:09

Jere_Sumell


2 Answers

UPDATE: This question was the subject of my blog in April 2015; thanks for the interesting question!


Your first question is:

The checked keyword is useful, but how about the unchecked keyword? I really can't find a use for it. Is there any?

The C# design team is not in the habit of adding features that have no use to the language. (With the notable exception of the unary plus operator, the world's most useless operator.)

The unchecked keyword has two main use cases.

First, constant integer arithmetic is always checked by default. This can be irritating. Suppose for example you have some interop code and you wish to create a constant for the HRESULT E_FAIL:

const int E_FAIL = 0x80004005; 

That's an error because that number is too big to fit into an int. But you might not want to use a uint. You might think well I'll just say

const int E_FAIL = (int)0x80004005; 

But that is also illegal because constant arithmetic including conversions is always checked by default.

What you have to do is turn off checked constant arithmetic via

const int E_FAIL = unchecked((int)0x80004005); 

Second, the default arithmetic for non-constant integer math in C# is unchecked, because it is faster, and because that is what many other similar languages do. However C# allows you to change the default to checked arithmetic for non-constant integer math via a compiler flag. If you've done so, and you need to turn it back off again on a temporary basis, then you have to use the unchecked block or expression syntax.

A third use case is to use the unchecked block as a form of self-documenting code, to say "I am aware that the operation I'm doing here might overflow, and that's fine with me." For example, I'll often write something like:

int GetHashCode() {     unchecked      {         int fooCode = this.foo == null ? 0 : this.foo.GetHashCode();         int barCode = this.bar == null ? 0 : this.bar.GetHashCode();         return fooCode + 17 * barCode;     } } 

The "unchecked" emphasizes to the reader that we fully expect that multiplying and adding hash codes could overflow, and that this is OK.

Your second question is:

What's the difference between these two approaches to handle overflow?

Good question.

If in your checked context you mean: I expect arithmetic to always be within bounds; if it is not then my program has a serious bug and must be terminated before it does more harm to the world then you should not do any overflow checking at all, because there are no overflows. Any exception should terminate the program; the checked context is simply making the runtime do work to verify the correctness of your code.

If in your checked context you mean I require arithmetic to be within bounds but I obtained this data from an untrustworthy source and I am too lazy to do range checking on it then you should catch the exception. However, the better practice would be to do range checking and give a more meaningful error if the data is out of range, than to have the runtime notice the problem and throw an overflow exception. I would strongly recommend range checking rather than catching an exception; don't be lazy.

like image 174
Eric Lippert Avatar answered Oct 13 '22 22:10

Eric Lippert


I'm not quite sure about performance implications of checked and unchecked. In theory, unchecked should be more performant and it is the default context. Unless you hang around the boundaries of integer types for some kind of special algorithm/business logic etc., using checked is rarely necessary/useful/readable.

As I said, unchecked is the default context so why do you need an unchecked keyword? One thing could be to be explicit about the type of a context where there's a high usage of checked contexts. The other is to use unchecked context inside checked context:

checked {     int a = 5 + 1231;      unchecked {         a += 221;     } } 

Your question might be why the default context is unchecked. I guess it's a design choice by Microsoft.

Their difference is that checked context checks if there is an overflow for each arithmetic operation and raises an exception if there is an overflow.

like image 31
mostruash Avatar answered Oct 13 '22 22:10

mostruash