.NET Integer Implementation Can Add Up to Trouble

Introduction

This article addresses an issue with the implementation of Integer values in .NET that one should be aware of when performing calculations on integer values that may overrun the maximum or minimum values of the integer type.  Oddly enough, or at least it seems odd to me, when the integer value mechanization details were ironed out it was apparently decided that the best way to normally handle overrunning the maximum or minimum values of an integer would be to simply wrap to the opposite end of available values without throwing an error.  That can certainly lead to rather disastrous results in calculations that may creep up on either of the extreme ends of the possible range of values.

Normally one would mitigate this by selecting a different data type less likely to be overrun by exceeding either the minimum or maximum values acceptable for that integer type.  However, .NET does offer the means to force throwing an error when the upper or lower limits of the data are going to be exceeded by any given calculation; it does take a little more work to safely implement such calculations but not much; it is certainly worth having the peace of mind that comes from knowing that wrapping the values will be eliminated in the event that an overrun is going to occur.

Attached Project

The attached project contains a single Windows Forms project that provides examples of unsafe and safe calculations involving addition and subtraction of numbers at the minimum and maximum limits of the integer type.

There are four examples used to illustrate the point:
  • Adding one to the maximum integer value without using the 'checked' function.
  • Adding one to the maximum integer value whilst using the 'checked' function.
  • Subtracting one from the minimum integer value without using the 'checked' function.
  • Subtracting one from the minimum integer value whilst using the 'checked' function.
To the point, if you add one to the maximum value without using the 'checked' function, the result will wrap to become the minimum possible integer values.

Similarly, if you subtract one from the minimum integer value without using the 'checked' function, the result will be the maximum possible integer value.
Once ran, the application is per the following figure:

.NETInteger1.jpg 

Figure 1:  Test Application

At the top of the form are the minimum and maximum values for an integer on my machine.  The two groups below either add one to the maximum value or subtract one from the minimum value.  The top option does not use the 'checked' function and it does not throw an error.  If you click the button you will see the result or adding one, for example, to the maximum value is in fact now the minimum value.  Maybe not exactly what you had in mind for the result.

The bottom option of each test performs the same calculaton but they both rely on the 'checked' function to prevent the overflow.  In those cases, the attempt will result in an exception which is in turn caught in a try-catch block and used to display an error message to the user.

The code for the project is annotated and you can follow along with it by reading the comments and examining the code.  At the end of it, the value of using the 'checked' function should be relatively obvious.

Main Form Code

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace AddsUp
{
    public partial class Form1 : Form
    {
        // set up two integer values to
        // contain the minimum and maximum
        // integer values
        int MaxValue;
        int MinValue;
        public Form1()
        {
            InitializeComponent();
            // set the variables to min and max value
            MaxValue = int.MaxValue;
            MinValue = int.MinValue;
            // display the minimum and maximum values
            lblMaxValue.Text = lblMaxValue.Text + ":  " + MaxValue.ToString();
            lblMinValue.Text = lblMinValue.Text + ":  " + MinValue.ToString();
            // preload the textboxes used in the calculations
            txtMaxValue.Text = MaxValue.ToString();
            txtCheckedMaxValue.Text = MaxValue.ToString();
            txtMinValue.Text = MinValue.ToString();
            txtCheckedMinValue.Text = MinValue.ToString();
        }
        private void Form1_Load(object sender, EventArgs e)
        {
        }
        /// <summary>
        /// Unchecked, overrunning the maximum integer value will force the
        /// number to wrap; that is, adding one to the maximum integer value
        /// will not throw an error and it will wrap the value to the minimum
        /// integer value.  Change the number subtracted from 1 to 10 or any
        /// larger value and note the effect; certainly not anything you'd want
        /// to see in anything important and involving calculations.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnMaxPlus1_Click(object sender, EventArgs e)
        {
            try
            {
                if (!String.IsNullOrEmpty(txtMaxValue.Text))
                    txtMaxPlus1Result.Text =Convert.ToString(Convert.ToInt32(txtMaxValue.Text) + 1);
            }
            catch(Exception ex)
            {
                MessageBox.Show(ex.Message, "Error");
            }
        }
        /// <summary>
        /// Checking the calculation will, instead of wrapping to the minimum
        /// value, force the calculation to throw an overflow exception.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnMaxValuePlus1Checked_Click(object sender, EventArgs e)
        {
            try
            {
                if (!String.IsNullOrEmpty(txtCheckedMaxValue.Text))
                {
                    int result = checked(Convert.ToInt32(txtCheckedMaxValue.Text) + 1);
                    txtCheckedMaxValueResult.Text = result.ToString();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error");
            }
        }
        /// <summary>
        /// As with overrunning the maximum value, subtracting one or more from the
        /// minimum value will, unchecked, wrap to the maximum value.  Again,
        /// vary the amount subtracted from the minimum value and note the
        /// impact of wrapping the values.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnMinValueMinus1_Click(object sender, EventArgs e)
        {
            try
            {
                if (!String.IsNullOrEmpty(txtMinValue.Text))
                    txtMinValueMinus1Result.Text =Convert.ToString(Convert.ToInt32(txtMinValue.Text) - 1);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error");
            }
        }
        /// <summary>
        /// Checking here to can divert disaster by throwing an overflow
        /// exception when the minimum value is exceeded through subtraction.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnCheckedMinValueMinus1_Click(object sender, EventArgs e)
        {
            try
            {
                if (!String.IsNullOrEmpty(txtCheckedMinValue.Text))
                {
                    int result = checked(Convert.ToInt32(txtCheckedMinValue.Text) - 1);
                    txtCheckedMinValueMinus1.Text = result.ToString();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error");
            }
        }
        private void btnExit_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }
    }
}


Similar Articles