# V204. Explicit conversion from 32-bit integer type to pointer type.

Анализатор обнаружил явное приведение 32-битного целочисленного типа к указателю. Ранее подобную ситуацию можно было выявить с помощью диагностического правила V201. Однако явное приведение типа `int` к указателю гораздо опаснее, чем приведение `int` к типу `intptr_t`. Поэтому было создано отдельное правило для поиска явного приведения типов при работе с указателями.

Пример некорректного кода.

    int n;
    float *ptr;
    ...
    ptr = (float *)(n);

В 64-битной программе тип `int` имеет размер 4 байта и не может вместить в себя указатель размером 8 байт. Приведение типа, как показано в примере, практически всегда свидетельствует о наличии ошибки.

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

Если по каким-то причинам необходимо хранить указатель в переменной целочисленного типа, то для этого следует использовать memsize-типы данных. Например: `size_t`, `ptrdiff_t`, `intptr_t`, `uintptr_t`.

Пример корректного кода:

    intptr_t n;
    float *ptr;
    ...
    ptr = (float *)(n);

Возможна специфическая ситуация, когда указатель допустимо хранить в 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" (USER and GDI handles are sign extended 32b values).

Такие указатели можно хранить в 32-битных типах данных (например, `int`, `DWORD`). Для преобразования таких указателей к 32-битным типам и обратно используются специальные функции:

    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 )