﻿# V128\. A variable of the memsize type is read from a stream\. Consider verifying the compatibility of 32 and 64 bit versions of the application in the context of a stored data\.


> Это правило входит в группу "Диагностика 64\\\-битных ошибок"\\\. Разработка правил этой группы больше не ведётся, и в будущем они могут быть отключены\\\. Если вы используете эти правила, \[свяжитесь с нашей поддержкой\]\(https://pvs\-studio\.ru/ru/about\-feedback/\) — мы поможем найти замену или предложим альтернативное решение\\\.

Анализатор обнаружил потенциальную ошибку, связанную с несовместимостью данных, которыми обменивается 32\-битная и 64\-битная версия программы\. В поток записываются или из потока читаются переменные memsize\-типа\. Ошибка может заключаться в том, что данные записанные в бинарный файл в 32\-х битном приложении будут некорректно прочитаны 64\-х битном приложением\.

Рассмотрим пример такого кода:

```cpp
std::vector<int> v;
....
ofstream os("myproject.dat", ios::binary);
....
os << v.size();
```

Функция 'size\(\)' возвращает значение с типом [size\_t](https://pvs-studio.ru/ru/blog/terms/0044/)\. Его размер различен в 32\-х и 64\-х битных приложениях\. Соответственно, в файл будет записано различное количество байт\.

Способов избежать несовместимости данных достаточно много\.  Самый простой и грубый способ, это жестко задать размер читаемых и записываемых типов\. Пример такого кода:

```cpp
std::vector<int> v;
....
ofstream os("myproject.dat", ios::binary);
....
os << static_cast<__int64>(v.size());
```

Естественно, жёсткий переход на 64\-битные типы данных нельзя назвать хорошим решением\. Например, этот способ не позволит читать данные, записанные старой 32\-битной программой\. Если читать и записывать данные как 32\-битные значения, возникнет другая проблема\. В этом случае, 64\-битная программа не сможет записать информацию о массивах, состоящих более чем из 2^32 элементов\. Это может быть неприятным ограничением\. Ведь часто 64\-битные программы создаются именно для того, чтобы работать с огромными массивами данных\.

Выходом из этой ситуации может стать внесения понятия версии сохраненных данных\. Например, 32\-битная программа сможет открывать файлы, созданные только 32\-битной версией\. А 64\-битная программа будет работать с данными, сгенерированными как 32\-битной, так и 64\-битной версией программы\.

Ещё один вариант решения проблемы совместимости данных это хранение их в текстовом виде, или использовании XML формата данных\.

Следует отметить, что далеко не во всех программах имеет место проблема совместимости данных\. Если программа не создает проекты и иные файлы, которые нужно открывать на других компьютерах, то диагностику V128 можно просто отключить\.

Также, нет смысла беспокоиться, если поток используется для распечатки значений на экране\. PVS\-Studio, по возможности, пытается определить такие ситуации и не выдавать сообщения\. Однако, появление  ложных сообщений весьма вероятно\. В этом случае, вы можете воспользоваться одним из механизмов подавления ложных предупреждений, описанных в документации\.



**Дополнительные возможности**

По просьбе пользователей реализована возможность самостоятельно указать, какие из функций используются для сохранения/чтения данных\. Если в эти функции передаются memsize\-типы, то это считается опасным кодом\.

Формат расширения следующий: возле прототипа функции \(или возле её реализации, или в общем заголовочном файле\) пишется комментарий специального вида\. Начнём с примера использования:

```cpp
//+V128, function:write, non_memsize:2
void write(string name, char);
void write(string name, int32);
void write(string name, int64);
foo()
{
  write("zz", array.size()); // warning V128
}
```

Формат:

* **Ключ function** задаёт имя функции, на которую будет обращать внимание анализатор\. Это обязательный ключ – без его указания расширение, разумеется, работать не будет\.
* **Ключ class** – необязательный ключ, который позволяет указать класс, к которому относится функция \(то есть в этом случае – метод класса\)\. Без указания этого ключа анализатор будет обращать внимание на все функции с данным именем, с указанием – лишь на методы указанного класса\.
* **Ключ namespace** – необязательный ключ, который позволяет указать пространство имён, к которому относится функция\. Без указания ключа, опять же, анализатор будет обращать внимание на все функции, с указанием – лишь на функции, принадлежащие к заданному параметром пространству имён\. Ключ может быть задан совместно с ключом class – тогда анализатор будет обращать внимание лишь на методы некоторого класса из некоторого пространства имён\.
* **Ключ non\_memsize** позволяет задавать номер аргумента, в который нельзя погружать аргумент меняющегося в зависимости от архитектуры размера\. Номера считаются с единицы\. Также имеется техническое ограничение – этот номер не должен превышать число 14\. Ключей non\_memsize может быть задано несколько, если требуется обращать внимание сразу на несколько аргументов\.

Уровень диагностики в случае срабатывания на пользовательской функции – всегда первый\.

Напоследок дадим наиболее полный пример использования:

```cpp
// Предупреждать, когда в метод C класса B
// из пространства имён A во второй или третий
// аргумент была помещена переменная типа memsize:
//+V128,namespace:A,class:B,function:C,non_memsize:3,non_memsize:2
```