﻿# V3134\. Shift by N bits is greater than the size of type\.

Анализатор обнаружил потенциальную ошибку, связанную со сдвигом целого числа на 'N' бит, при этом 'N' больше размера этого числового типа в битах\.

Давайте рассмотрим пример:

```cpp
UInt32 x = ....;
UInt32 y = ....;
UInt64 result = (x << 32) + y;
```

В данном случае хотели собрать 64\-битное число из 2\-х 32\-битных, сдвинув 'x' на 32 бита и сложив старшую и младшую часть\. Но поскольку 'x' в момент сдвига является 32\-битным числом, то сдвиг на 32 бита эквивалентен сдвигу на 0 бит, что приведет к некорректному результату\.

Корректный вариант может выглядеть так:

```cpp
UInt32 x = ....;
UInt32 y = ....;
UInt64 result = ((UInt64)x << 32) + y;
```



Также давайте рассмотрим пример из реального проекта:

```cpp
static long GetLong(byte[] bits)
{
  return ((bits[0] & 0xff) << 0)
       | ((bits[1] & 0xff) << 8)
       | ((bits[2] & 0xff) << 16)
       | ((bits[3] & 0xff) << 24)
       | ((bits[4] & 0xff) << 32)
       | ((bits[5] & 0xff) << 40)
       | ((bits[6] & 0xff) << 48)
       | ((bits[7] & 0xff) << 56);
}
```

В методе 'GetLong' выполняется преобразование массива байт в 64\-битное число\. Поскольку операторы битового сдвига определены только для 32 и 64\-битных чисел, то каждый байт будет неявно преобразован в 'Int32'\. Диапазон битового сдвига 32\-битного числа \- \[0\.\.31\], поэтому преобразование будет выполняться корректно только для первых 4 байт массива\.

Если предположить, что массив байт был сформирован из 64\-битного числа \(К примеру из 'Int64\.MaxValue'\), то при обратном преобразовании из массива байт в Int64 данным методом возможна ошибка, в случае, если изначальное число не находилось в диапазоне \[Int32\.MinValue\.\.\.\.Int32\.MaxValue\]\.

Для большей наглядности давайте рассмотрим работу данного кода для числа '289077008695033855'\. Данное число после преобразования в массив байт будет иметь вид:

```cpp
289077008695033855 => [255, 255, 255, 255, 1, 2, 3, 4]
```

Передав этот массив байт в метод 'GetLong' перед операцией сдвига каждый байт будет неявно преобразован в Int32\. Давайте выполним каждую операцию сдвига отдельно, чтобы понять в чем проблема\.

![V3134_ru/image1.png](https://import.viva64.com/docx/blog/V3134_ru/image1.png)

Как видим, сдвиг выполняется для 32\-битного числа, что в итоге приводит к пересечению диапазонов и как следствие к неправильному результату\. Это происходит потому, что при попытке сдвинуть 32\-битное число более чем на 32 бита мы начинаем сдвигать биты по кругу \(сдвиг на 32, 40, 48 и 56 бит идентичен сдвигу на 0, 8, 16 и 24 соответственно\)



Исправленный вариант данного метода мог бы выглядеть так:

```cpp
static long GetLong(byte[] bits)
{
  return ((long)(bits[0] & 0xff) << 0)
       | ((long)(bits[1] & 0xff) << 8)
       | ((long)(bits[2] & 0xff) << 16)
       | ((long)(bits[3] & 0xff) << 24)
       | ((long)(bits[4] & 0xff) << 32)
       | ((long)(bits[5] & 0xff) << 40)
       | ((long)(bits[6] & 0xff) << 48)
       | ((long)(bits[7] & 0xff) << 56);
}
```

Рассмотрев каждую операцию сдвига отдельно, мы увидим, что теперь сдвиг выполняется для 64\-битного числа, что в итоге препятствует пересечению диапазонов\.

![V3134_ru/image3.png](https://import.viva64.com/docx/blog/V3134_ru/image3.png)