вторник, 28 июня 2011 г.

Операторы checked /unchecked и цикл for в C#


В этой статье поговорим немножко о цикле for и об операторах checked /unchecked.

Циклом называется один или несколько операторов, повторяющихся заданное число раз или до тех пор, пока не будет выполнено определенное условие. Выбор типа цикла зависит от задачи программирования и личных предпочтений кодирования. 
Оператор for повторно выполняет заключенный в цикл оператор (или несколько операторов) следующим образом.
  •        Сначала вычисляется начальное значение параметра цикла.
  •          Затем, пока условие получает значение true, оператор в теле цикла выполняется и затем происходит новое вычисление параметра цикла.
  •          Когда условие получает значение false, управление передается вне цикла.

Поскольку тестирование условного выражения осуществляется до выполнения цикла, оператор for выполняется ноль или более раз. Все выражения оператора for являются необязательными.  

Рассмотрим следующий пример. Попробуйте ответить на вопросы в тексте программы.


using System.IO;
using System.Diagnostics;
using System.Threading;
using System.Runtime.InteropServices;

namespace Tests
{
    class Program
    {
        #region Вопрос

        /* Вопрос (если не указан другой):
         
            Что произойдет при запуске программы?
           1. Ошибка компиляции. В каком месте?
           2. Ошибка выполнения. В каком месте? Что успеет вывестись на консоль?
           3. Ошибок не будет. Что будет выведено на консоль?
        */

        #endregion

        static void Main(string[] args)
        {
            #region Cycle

            for (int i = int.MaxValue - 10; i <= int.MaxValue; i++)
            {
                Console.WriteLine("a");
            }

            #endregion

            Console.ReadLine();
        }
    }
}


Ответ:  Обычно человек отвечает что буква “a” выведется 10 раз на консоль, после чего выполнение программы прекратится, однако не тут то было J Результат довольно неожиданный.
Буква “a” будет выведена бесконечное количество раз, программа зациклится. Так как при выполнении цикла, когда i уже равняется максимальному значению, в цикле к i прибавляется ещё 1 и происходит переполнение.  По умолчанию неконстантные выражения не проверяются на переполнение во время выполнения, и они не создают исключений переполнения. И тогда i станет равной minValue, и цикл продолжит свою работу. 

Почему же если прибавить к maxValue один получается minValue? Опустимся на уровень байтов и посмотрим ,что же происходит. Есть, например байт 11111111 - это максимум, если к нему прибавить 1, то будет 1 0000 0000, первая 1 выходит за байт, следовательно  остается 0000 0000, а это минимальное значение.

Проверку переполнения можно включить посредством параметров компилятора, настройки среды или использования ключевого слова checked. В следующем примере демонстрируется использование выражения checked или блока checked для обнаружения переполнения, возникающего в результате увеличения i во время выполнения. 

Рассмотрим следующий пример.

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Diagnostics;
using System.Threading;
using System.Runtime.InteropServices;

namespace Tests
{
    class Program
    {

        #region Вопрос

        /* Вопрос (если не указан другой):
         
            Что произойдет при запуске программы?
           1. Ошибка компиляции. В каком месте?
           2. Ошибка выполнения. В каком месте? Что успеет вывестись на консоль?
           3. Ошибок не будет. Что будет выведено на консоль?
        */

        #endregion

        static void Main(string[] args)
        {

            #region AnotherCycle

            checked
            {
                for (int i = int.MaxValue - 10; i <= int.MaxValue; i++)
                {
                    Console.WriteLine("a");
                }
            }

            #endregion

            Console.ReadLine();
        }
    }
}


Ответ:  На консоль выведется десять раз буква “a”  после чего возникнет исключение System.OverflowException,  где Message="Переполнение в результате выполнения арифметической операции".

Почему такое происходит. Конечно же, причина кроется в операторе checked. Что же это за оператор, рассмотрим его подробнее?


Операторы C# могут выполняться в проверяемом или непроверяемом контексте. В проверяемом контексте арифметическое переполнение вызовет исключение. В непроверяемом контексте арифметическое переполнение будет проигнорировано, а результат усечен.

·         checked   -  используется для явного включения проверки переполнения при выполнении арифметических операций и преобразований с данными целого типа. По умолчанию выражение, содержащее только константные значения, вызывает ошибку компилятора в том случае, если результат его вычисления выходит за допустимые пределы значений конечного типа. Если выражение содержит одно или несколько неконстантных значений, компилятор не выполняет проверку переполнения. 
·         unchecked   - используется для подавления проверки переполнения при выполнении арифметических операций и преобразований с данными целого типа. Если в непроверяемом контексте результатом выполнения выражения является значение, выходящее за допустимые пределы значений конечного типа, то переполнение не помечается. Вычисление в приведенном ниже примере выполняется в блоке или выражении unchecked, поэтому факт превышения результатом максимального значения целого числа игнорируется.

Если не указано ни checked, ни unchecked, контекст по умолчанию зависит от внешних факторов, например параметров компилятора.

Проверка переполнений влияет на следующие операции.

·         Выражения, использующие следующие предопределенные операторы в целых типах:
++   —   - (унарный)   +   -   *   /
·         Явные числовые преобразования между целыми типами данных.

С помощью параметра компилятора /checked можно указать проверяемый или непроверяемый контекст для всех целочисленный арифметических операторов, которые явно не выражены в области действия ключевого слова checked или unchecked.
Надеюсь вам была интересна данная статья. В следующей статье мы рассмотрим такие темы как наследование, и коснёмся темы статических конструкторов.


1 комментарий:

  1. На консоль выведется десять раз буква “a”? 11 раз ведь?

    ОтветитьУдалить