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

Автор: | 21.12.2017

В статье рассмотрен вопрос переполнения типов данных, используемых для хранения целых чисел в языке 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#» Джеффри Рихтер

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

Поделиться
Share on VK
VK
Tweet about this on Twitter
Twitter
Share on Facebook
Facebook

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

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