Безопасные вычисления на C#

В статье рассмотрен вопрос переполнения типов данных, используемых для хранения целых чисел в языке C# (.NET), и способы обработки подобных ситуаций.

В языках программирования, таких как C, C++, C#, Java для работы с числовыми данными существует довольно много типов данных. Для операций с числами с плавающей запятой это, как правило, типы подобные float и double. Для операций с целыми числами – это byte, short, int, long и т.д., плюс варианты данных типов без знака, все они отличаются размером памяти, которая выделяется для хранения числа. В этой статье остановимся на особенностях работы с целыми числами в C#.

Язык C# предоставляет следующие типы для работы с целыми числами.

Тип Описание
sbyte 8-разрядное число со знаком
byte 8-разрядное число без знака
short 16-разрядное число со знаком
ushort 16-разрядное число без знака
int 32-разрядное число со знаком
uint 32-разрядное число без знака
long 64-разрядное число со знаком
ulong 64-разрядное число без знака

Для наших экспериментов напишем следующую программу.

using System;

namespace simple
{
    class Program
    {
        static void Main(string[] args)
        {
            byte a = 7;
            Console.WriteLine("out: " + a);
        }
    }
}

Если вы ее откомпилируете и запустите, то на экране будет выведена строка:

 out: 7

Далее все модификации кода будут касаться тела метода Main.

Изменим программу следующим образом.

byte a = 9;
byte b = 7;
byte c = (byte)(a + b);
Console.WriteLine("out: " + c);

Результат сложения a и b необходимо привести к типу byte, т.к. по умолчанию тип суммы – это intРабота этой программы вполне предсказуема, мы получим следующее:

 out: 16

Если изменить значения a и b так, чтобы их сумма стала больше 255:

byte a = 150;
byte b = 244;
byte c = (byte)(a + b);
Console.WriteLine("out: " + c);

Результат не столь тривиален (хотя для опытных разработчиков, он вполне закономерен):

 out: 138

Данный ответ получился из-за того, что в переменной типа byte не может храниться число большее, чем 255, если мы приводим к данному типу значение большее, чем этот порог (в нашем случае это 150 + 244 = 394), то произойдет переполнение. Число 138 получилось следующим образом: из 394 мы должны вычитать 256 до тех пор, пока разность не станет меньше 255, в данном примере это нужно сделать один раз: 394 – 256 = 138. Самое неприятное заключается в том, что такая ситуация может произойти довольно неожиданно, и мы получим некорректный результат в процессе вычисления на “отлаженной и протестированной” программе, где-нибудь в продакшине. Если это критично, то мы может сделать арифметические операции проверяемыми на переполнение. При запуске такого кода, при переполнении, произойдет выброс исключения OverflowException.

byte a = 150;
byte b = 244;
byte c = checked((byte)(a + b));
Console.WriteLine("out: " + c);

Оператор checked следит за тем, чтобы в переданном ему выражении не было переполнения. Его можно записать в другом виде, более удобном для случая, когда вычисление требует нескольких операций.

byte a = 150;
byte b = 244;
byte c = 0;
checked
{
    a += 10;
    c = ((byte)(a + b));
}
Console.WriteLine("out: " + c);

Проверку на переполнение можно включить глобально, для всех вычислений, для этого нужно Visual Studio зайти в свойства проекта, перейти на вкладку Build и нажать там на кнопку “Advanced…”. В результате откроется окно с настройками.

Настройка глобальной проверки переполнения

В нем можно поставить (или убрать) галочку в поле “Check for arithmetic overflow/underflow”. Если установить галочку, то все вычисления будут проверяться на переполнение, и если оно произойдет, то будет выброшено исключение OverflowException. В таком случае можно отдельно создавать блоки кода, в которых данная проверка производиться не будет, для этого используется оператор unchecked. Это может выглядеть так:

unchecked
{
    a += 10;
    c = ((byte)(a + b));
}

Более подробно вопросы, связанные с вычислениями и типами данных, представлены в книге:

Книга «CLR via C#. Программирование на платформе Microsoft.NET Framework 4.5 на языке C#» Джеффри Рихтер - купить на OZON.ru книгу CLR via C# с быстрой доставкой | 978-5-496-00433-6 «CLR via C#. Программирование на платформе Microsoft.NET Framework 4.5 на языке C#» Джеффри Рихтер

На этом всё! Спасибо! Корректных вам вычислений!

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *