>
>
>
V204. Explicit conversion from 32-bit i…


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 )

Дополнительные материалы по данной теме: