﻿# Урок 16\. Паттерн 8\. Memsize\-типы в объединениях

Особенностью объединения \(union\) является то, что для всех элементов \(членов\) объединения выделяется одна и та же область памяти, то есть они перекрываются\. Хотя доступ к этой области памяти возможен с использованием любого из элементов, элемент для этой цели должен выбираться так, чтобы полученный результат был осмысленным\.

Следует внимательно отнестись к объединениям, имеющим в своем составе указатели и другие члены типа [memsize](https://pvs-studio.ru/ru/blog/terms/0030/)\.

Когда возникает необходимость работать с указателем как с целым числом, иногда удобно воспользоваться объединением, как показано в примере, и работать с числовым представлением типа без использования явных приведений:

```cpp
union PtrNumUnion {
  char *m_p;
  unsigned m_n;
} u;
u.m_p = str;
u.m_n += delta;
```

Данный код корректен на 32\-битных системах и некорректен на 64\-битных\. Изменяя член m\_n на 64\-битной системе, мы работаем только с частью указателя m\_p \(смотри рисунок 1\)\.

![16_Pattern_08_Memsize-types_in_unions_ru/image1.png](https://import.viva64.com/docx/blog/16_Pattern_08_Memsize-types_in_unions_ru/image1.png)

_Рисунок 1 \- Формат объединения на 32\-битной и 64\-битной системе_

Следует использовать тип, который будет соответствовать размеру указателя:

```cpp
union PtrNumUnion {
  char *m_p;
  size_t m_n; //type fixed
} u;
```

Другое частое использование объединения \- это представление одного члена, набором других более мелких\. Например, нам может потребоваться разбить значение типа [size\_t](https://pvs-studio.ru/ru/blog/terms/0044/) на байты для реализации табличного алгоритма подсчета количества нулевых битов:

```cpp
union SizetToBytesUnion {
  size_t value;
  struct {
    unsigned char b0, b1, b2, b3;
  } bytes;
} u;
   
SizetToBytesUnion u;
u.value = value;
size_t zeroBitsN = TranslateTable[u.bytes.b0] +
                   TranslateTable[u.bytes.b1] +
                   TranslateTable[u.bytes.b2] +
                   TranslateTable[u.bytes.b3];
```

Здесь допущена принципиальная алгоритмическая ошибка, заключающаяся в предположении, что тип size\_t состоит из 4 байт\. Возможность автоматического поиска алгоритмических ошибок пока вряд ли возможна, но мы можем осуществить поиск всех объединений и проверить наличие в них memsize\-типов\. Найдя такое объединение, мы можем обнаружить алгоритмическую ошибку и переписать код следующим образом\.

```cpp
union SizetToBytesUnion {
  size_t value;
  unsigned char bytes[sizeof(value)];
} u;
   
SizetToBytesUnion u;
u.value = value;
size_t zeroBitsN = 0;
for (size_t i = 0; i != sizeof(bytes); ++i)
  zeroBitsN += TranslateTable[bytes[i]];
```

## Диагностика

Инструмент [PVS\-Studio](https://pvs-studio.ru/ru/pvs-studio/) позволяет быстро найти и просмотреть в коде программы все объединения, содержащие memsize типы\. Анализатор выдает диагностическое сообщение [V117](https://pvs-studio.ru/ru/docs/warnings/v117/) для структур, на которые следует обратить внимание программисту при переносе кода на 64\-битную систему\.

_Авторы курса: Андрей Карпов \([karpov@viva64\.com](mailto:karpov@viva64.com)\), Евгений Рыжков \([evg@viva64\.com](mailto:evg@viva64.com)\)\._

_Правообладателем курса "Уроки разработки 64\-битных приложений на языке Си/Си\+\+" является ООО "Системы программной верификации"\. Компания занимается разработкой программного обеспечения в области анализа исходного кода программ\. [Сайт компании](https://pvs-studio.ru/ru/pvs-studio/)\._