﻿# Как корректно привести указатель к int в 64\-битной программе?

Наиболее общий ответ \- никак\.

В 64\-битных программах размер указателя равняется 64\-битам и его нельзя поместить в тип int, который остался 32\-битным практически на всех системах\. К исключению относятся экзотические системы с [моделью данных](https://pvs-studio.ru/ru/blog/terms/0012/) SILP64, где размер int также 64\-битный\. В наиболее распространенных операционных системах \(Window, Linux, macOS, \.\.\.\) используются модели данных [LP64](https://pvs-studio.ru/ru/blog/terms/0028/) и [LLP64](https://pvs-studio.ru/ru/blog/terms/0026/), в которых int занимает 32\-бита\.

Помещение 64\-битного указателя в 32\-битную переменную ведет к обрезанию старших разрядов и как следствие к некорректной работе программы\. Подобный код в программах недопустим:

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

Дополнительная опасность подобного кода заключается в том, что он скрывает ошибку, которая может обнаружить себя не сразу\. Пока указатели ссылаются на объекты, созданные в младших адресах памяти, программа будет работать корректно, причем возможно долгое время\. Однако это только видимость работоспособности программы и сбой может произойти в любой момент \(см\. [пример](https://pvs-studio.ru/ru/blog/posts/cpp/0033/)\)\. 

Если по каким\-то причинам программисту необходимо хранить указатели в целочисленных типах, то для этого он может использовать [memsize\-типы](https://pvs-studio.ru/ru/blog/terms/0030/), например, [intptr\_t](https://pvs-studio.ru/ru/blog/terms/0023/), [size\_t](https://pvs-studio.ru/ru/blog/terms/0044/), [INT\_PTR](https://pvs-studio.ru/ru/blog/terms/0024/) и так далее\.

Есть все\-таки специфическая ситуация, когда указатель допустимо хранить в 32\-битных типах\. Речь идет о дескрипторах \(handles\), которые используются в Windows для работы с различными системными объектами\. Примеры таких типов: HANDLE, HWND, HMENU, HPALETTE, HBITMAP и так далее\. По сути, эти типы являются указателями\. Например, HANDLE объявляется в заголовочных файлах как "typedef void \*HANDLE;"\.

Хотя дескрипторы являются 64\-битными указателями, для большей совместимости \(например, для возможности взаимодействия между 32\-битынми и 64\-битными процессами\) в них используется только младшие 32\-бита\. Подробнее смотри "[Microsoft Interface Definition Language \(MIDL\): 64\-Bit Porting Guide](https://msdn.microsoft.com/en-us/library/ms810720)" \(USER and GDI handles are sign extended 32b values\)\.

Такие указатели можно хранить в 32\-битным типам данных \(например, int, DWORD\)\. Для преобразования таких указателей к 32\-битным типам и обратно используются [специальные функции](https://msdn.microsoft.com/en-us/library/aa384267(VS.85).aspx):

```cpp
void            * Handle64ToHandle( const void * POINTER_64 h ) 
void * POINTER_64 HandleToHandle64( const void *h )
long              HandleToLong    ( const void *h )
unsigned long     HandleToUlong   ( const void *h )
void            * IntToPtr        ( const int i )
void            * LongToHandle    ( const long h )
void            * LongToPtr       ( const long l )
void            * Ptr64ToPtr      ( const void * POINTER_64 p )
int               PtrToInt        ( const void *p )
long              PtrToLong       ( const void *p )
void * POINTER_64 PtrToPtr64      ( const void *p )
short             PtrToShort      ( const void *p )
unsigned int      PtrToUint       ( const void *p )
unsigned long     PtrToUlong      ( const void *p )
unsigned short    PtrToUshort     ( const void *p )
void            * UIntToPtr       ( const unsigned int ui )
void            * ULongToPtr      ( const unsigned long ul )
```

Следует отметить, что простые ошибки приведения указателей к 32\-битным типам хорошо диагностируются компилятором Visual C\+\+\. Однако во многих старых проектах, содержащих большие сторонние библиотеки, часто бывают отключены многие предупреждения компилятора, что увеличивает вероятность пропуска такого типа ошибок\. В описанной ситуации имеет смысл использовать специализированное средство обеспечения переносимости кода на 64\-разрядную платформу, например разработанный нами статический анализатор кода [Viva64](https://pvs-studio.ru/ru/pvs-studio/)\.

## Библиографический список

1. Обсуждение на сайте bytes\.com\. [Cast from void\* to int](http://bytes.com/topic/c/answers/482159-cast-void-int)
1. Андрей Карпов, Евгений Рыжков\. [Паттерн 7\. Упаковка указателей](https://pvs-studio.ru/ru/blog/lessons/0015/)\.
1. Обсуждение на сайте stackoverflow\.com\. [Error: cast from void\* to int loses precision](https://stackoverflow.com/questions/1640423/error-cast-from-void-to-int-loses-precision)\.
1. Андрей Карпов\. [Что такое size\_t и ptrdiff\_t](https://pvs-studio.ru/ru/blog/posts/cpp/a0050/)\.
1. База знаний\. [Что такое макрос POINTER\_32 ?](https://pvs-studio.ru/ru/blog/posts/k0043/)