﻿# Поиск явного приведения указателя к 32\-битному типу

В компиляторе Visual Studio C\+\+ имеется warning C4311 \('variable' : pointer truncation from 'type' to 'type'\) предназначенный для выявления ошибок приведения указателя к 32\-битным типам данных\. В Intel C\+\+ этому предупреждению соответствует warning \#810\.

Пример обнаруживаемого дефекта:

```cpp
void *ptr = x;
int y = (int)ptr;
```

В Win64 размер указателя стал 64\-битным, а размер int остался по\-прежнему 32 бита\. Явное приведение типа обрежет значение указателя, что приведет к ошибке, если указатель ссылается на объект находящимся за пределами младших 4 Гбайт памяти \(0x00000000FFFFFFFF\)\.

Подобные ошибки коварны тем, что могут проявляться нерегулярно\. Однако их можно легко обнаружить, просмотрев все предупреждения компилятора с номером C4311\. Но вот с использованием самой этой проверки есть некоторый неприятный нюанс\.

Если вы просто создадите 64\-битный проект в Visual Studio 2008/2010, и напишите приведенный выше код, то вы не получите предупреждения C4311\. Разберемся в причинах этой неожиданной ситуации\. 

В Visual Studio 2003/2005 имеется ключ [/Wp64](https://pvs-studio.ru/ru/blog/terms/0057/) предназначенный для выявления некоторых проблем, с которыми столкнется программист при сборке своего кода в 64\-битном варианте\. К группе этих предупреждений относится и предупреждение C4311\. Если, создать проект в Visual Studio 2005, то даже в 32\-битной конфигурации для строки _int y \= \(int\)ptr;_ будет сгенерировано предупреждение:

```cpp
warning C4311: 'type cast' : 
pointer truncation from 'void *' to 'int'.
```

Ключ /Wp64 был предназначен, чтобы хоть как\-то подготовить приложения к 64\-битной платформе без необходимости создания 64\-битной конфигурации\. Однако, время "подготавливаться" прошло\. Начиная с Visual Studio 2005, имеется 64\-битный компилятор\. Если есть желание поддерживать Win32 и Win64 платформу, то необходимо иметь две конфигурации проекта\. В конфигурации x64 использовать ключ /Wp64 бессмысленно, и именно поэтому в Visual Studio 2008/2010 он объявлен устаревшим\.

Все было бы хорошо, но как мне кажется разработчики Visual Studio допустили логическую ошибку\. Если вы создадите новый проект в Visual Studio 2008/2010 или конвертируете старый проект в новый, то ключ /Wp64 будет не установлен\. Это правильно\. Если даже специально в "Additional Options" проекта прописать /Wp64,  то будет выдано сообщение:

```cpp
Command line warning D9035: 
option 'Wp64' has been deprecated 
and will be removed in a future release.
```

Юмор ситуации в том, что такие предупреждения как [C4311](https://msdn.microsoft.com/en-us/library/4t91x2k5.aspx), [C4312](https://msdn.microsoft.com/en-us/library/h97f4b9y.aspx), [C4313](https://msdn.microsoft.com/en-us/library/wbe05206.aspx) почему\-то по\-прежнему связаны с ключом /Wp64\. И если его нет, то и нет этих предупреждений, хотя уровень их опасности **Level 1**\.

Эти предупреждения вернутся, если включить /Wp64 и получить предупреждения D9035 об устаревшей  опции\. Другой вариант \- включить /Wall\. Сообщения будут выданы, но это путь, как вы понимаете, только для отважных\. Видимо наиболее разумным вариантом является использование [\#pragma warning](https://msdn.microsoft.com/en-us/library/2c8f766e(v=VS.100).aspx)  в stdafx\.h\.

Теперь перейдем к Intel C\+\+\. Начиная изучение вопроса, я ожидал, что в своем поведении относительно /Wp64 он эквивалентен Visual C\+\+\. Оказалось, что у него все по\-своему\. Ошибку приведения вида _int y \= \(int\)ptr;_ он обнаружил и без ключа /Wp64, выдав warning \#810\. А вот warning \#967 \(эквивалентный C4312\) уже требует /Wp64\. Получается, что в компиляторе Intel C\+\+ также есть набор предупреждений связанный с /Wp64, но сам этот набор другой\. Поскольку исторически сложилось, что с документацией по экзотическим особенностям Intel C\+\+ туго, то я не нашел что именно включает /Wp64\.

После всего этого потока мыслей у читателя может возникнуть вопрос:

**А в чем все\-таки заковырка то? Прошу еще раз кратко\.**

Ответ\. Если вы имеете проект для Visual Studio 2008/2010 и создадите 64\-битную конфигурацию, то вы не увидите предупреждения для таких банальных ошибок как:

```cpp
void *ptr = x;
int y = (int)ptr; // C4311

int i = x;
return (void*)i; // C4312

int * pI = 0;
printf("%d", pI); // C4313
```

И видимо некоторых других\. Собирая этот же проект с помощью Intel C\+\+, вы не увидите другой набор ошибок\.

Чтобы получить все эти благотворные предупреждения вы должны явно самостоятельно включить их\! Это не сложно сделать, при условии, что вы знаете про это\. Я вот долгое время не знал, хотя интересуюсь тематикой разработки 64\-битных приложений\.

Подчеркну, что победа над этими предупреждениями вовсе не означает корректность 64\-битной программы\. Это только означает, что были исправлены наиболее очевидные дефекты\. Так сказать "кто не спрятался, я не виноват"\. А вот для обнаружения "тех, кто спрятался" в большом проекте есть смысл использовать специализированные инструменты \([Viva64](https://pvs-studio.ru/ru/pvs-studio/)\)\.



Я конечно не первый заметил эту недоделку касательно 64\-битных предупреждений\. Совсем недавно [здесь](https://msdn.microsoft.com/en-us/library/yt4xw8fh.aspx) оставили комментарий на эту тему\. Обратите внимание, что критика совсем свежая\.

Из всего этого я могу сделать вывод, что люди только начинают интересоваться созданием Win64\-приложений\. Эту фразу я писал год назад, и сейчас опять повторил ее\. Это очень странно\. Я не верю, что можно разрабатывать нормальные программы, не интересуясь даже тем, где указатель запихивается в int\. Отсутствие массовых обсуждений в интернете подобных вопросов меня крайне смущает\. Я не понимаю, как устроен мир\.