﻿# 64\-битные ошибки: LONG, LONG\_PTR и привет из прошлого

В целом, 64\-битные ошибки \- дело минувших дней\. Мало кто сейчас занимается портированием кода с 32\-битной на 64\-битную систему\. Кому это было нужно, уже портировали свои приложения\. Кому не нужно, то им, пожалуй, и не понадобится\. Но иногда такие ошибки передают нам "привет"\.

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

Вспомнить про тему 64\-битных ошибок меня заставила публикация "[Adventures in application compatibility: The case of the display control panel crash on exit](https://devblogs.microsoft.com/oldnewthing/20230213-00/?p=107823)"\. Возможно, наши читатели не знают или забыли, что статический анализатор PVS\-Studio начинался как инструмент для поиска 64\-битных ошибок\. В то время он назывался Viva64\. Так что тема 64\-битных ошибок нам очень близка и вызывает ностальгию :\)\.

Под 64\-битными ошибками мы понимаем такие дефекты к коде, которые проявляют себя при переносе приложения с 32\-битной на 64\-битную платформу\. Т\.е\. код был некорректен всегда, но на 32\-битной платформе в силу везения он работал без сбоев\. Рассмотрим простейший синтетический пример:

```cpp
void *ptr = foo();
unsigned num = (unsigned)(ptr);
ptr = (void *)(num);
```

Кто\-то решил на некоторое время сохранить значение указателя в переменной типа _unsigned_\. Этот код некорректный\. Однако в 32\-битной системе размеры указателя и переменной типа _unsigned_ совпадают, поэтому всё работает\. Проблема возникнет на 64\-битной системе, где скорее всего тип _unsigned_ будет по\-прежнему 32\-битным, а указатели станут 64\-битными\. Выполнение приведённого выше кода приведёт к потере старших бит в указателе\. Чтобы этого не произошло, нужно заменить _unsigned_ на [_uintptr\_t_](https://pvs-studio.ru/ru/blog/terms/0050/)\.

Схожая ситуация как раз и описана в статье\. В старом Windows драйвере обнаружился код, где происходит приведение значение к типу _LONG_, а не к _LONGP\_PTR_:

```cpp
SetWindowLong(GetDlgItem(m_dlg, IDC_SOME_BUTTON),
  GWL_WNDPROC, (LONG)g_originalWndProc);
```

В Windows x64 принята [модель данных](https://pvs-studio.ru/ru/blog/terms/0012/) LLP64, в которой переменные типа _long_ \(и _LONG_\) остались 32\-битными, как и тип _int_\. В результате приведение к типу _LONG_ приводит к потере старших 32 бит\. Правильный вариант:

```cpp
SetWindowLong(GetDlgItem(m_dlg, IDC_SOME_BUTTON),
  GWL_WNDPROC, (LONG_PTR)g_originalWndProc);
```

В статье такая старая ошибка в старом драйвере потребовала правку прямо в исполняемом двоичном коде\. Принцип "чем позже ошибка обнаружена, тем сложнее и дороже её исправление" в действии\.

Если вы всё\-таки когда\-то столкнётесь с задачей портирования кода на 64\-битную систему или будете искать ошибки в уже портированном коде, то приходите к нам на сайт\. Здесь вы найдёте:

1. [Обстоятельное руководство по разработке 64\-битных приложений на C и C\+\+](https://pvs-studio.ru/ru/blog/lessons/full/);
1. Анализатор [PVS\-Studio](https://pvs-studio.ru/ru/pvs-studio/), в котором по\-прежнему есть [набор диагностик](https://pvs-studio.ru/ru/docs/warnings/#64CPP), помогающий выявлять 64\-битные ошибки\.