# V205. Explicit conversion of pointer type to 32-bit integer type.

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

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

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

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

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

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

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

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

Возможна специфическая ситуация, когда указатель допустимо хранить в 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 )

Рассмотрим пример:

    HANDLE h = Get();
    UINT uId = (UINT)h;

Анализатор не выдаёт здесь сообщение, хотя HANDLE — это указатель. Его значения всегда помещаются в 32-бита. Следует учитывать, что невалидные дескрипторы (handles) объявлены следующим образом:

    #define INVALID_HANDLE_VALUE ((HANDLE)(LONG_PTR)-1)

Поэтому некорректно ниже будет написать так:

    if (HANDLE(uID) == INVALID_HANDLE_VALUE)

Т.к. переменная `uID` беззнаковая, то значение указателя будет равно не 0xFFFFFFFFFFFFFFFF, а 0x00000000FFFFFFFF.

Для подозрительной проверки, где unsigned будет превращаться в указатель, будет выдано предупреждение V204.