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

The analyzer has detected explicit type casting of a pointer type to a 32-bit integer type. The V202 diagnostic rule used to detect such behavior, but explicit conversion of a pointer to the `int` type is much more dangerous than conversion of `intptr_t` to `int`. So, a separate diagnostic rule to search for explicit type conversions when handling pointers has been created.

Here is a sample of incorrect code.

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

The `int` type is 4 bytes in a 64-bit program, so it cannot store a pointer of 8 bytes. Type casting, as shown in the example above, usually indicates an error.

Such errors are particularly problematic as they may not manifest immediately. A program can store pointers in 32-bit variables and work correctly for some time as long as all the objects created in the program are located in low-order addresses of memory.

If you need to store a pointer in an integer variable for some reason, use memsize-types. For instance: `size_t`, `ptrdiff_t`, `intptr_t`, `uintptr_t`.

This is the correct code:

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

However, there is a specific case when you may store a pointer in 32-bit types—handles, which are used in Windows to work with various system objects. Here are examples of such types: `HANDLE`, `HWND`, `HMENU`, `HPALETTE`, `HBITMAP`, etc. They are actually pointers. For instance, `HANDLE` is defined in header files as `typedef void *HANDLE;`.

Although descriptors are 64-bit pointers, they use only 32-bit low-order pointers for better compatibility (for example, to enable interaction between 32-bit and 64-bit processes).You can find more details in "Microsoft Interface Definition Language (MIDL): 64-Bit Porting Guide" (USER and GDI handles are sign extended 32b values).

Such pointers can be stored in 32-bit data types (for instance, `int`, `DWORD`). Special functions are used to cast such pointers to 32-bit types and vice versa:

    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 )

Let's take a look at the following example:

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

The analyzer does not issue the message here, even though `HANDLE` is a pointer. Its values always fit into 32 bits. Note that invalid handles are declared as follows:

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

That's why the next line is incorrect:

    if (HANDLE(uID) == INVALID_HANDLE_VALUE)

Since the `uID` variable is unsigned, the pointer value will be 0x00000000FFFFFFFF, not 0xFFFFFFFFFFFFFFFF.

The analyzer issues the V204 warning for a suspicious check when unsigned turns into a pointer.