This is the code I have:
HWND WebformCreate(HWND hParent, UINT id)
{
return CreateWindowEx(0, WEBFORM_CLASS, _T("about:blank"),
WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, 0, 0, 100, 100, hParent,
(HMENU)id, GetModuleHandle(NULL), 0);
}
This is the warning I get:
warning C4312: 'type cast' : conversion from 'UINT' to 'HMENU' of greater size
These are the questions I have:
(HMENU)(UINT_PTR)id
gets rid of the warning. Why/how?Вы преобразуете 32-битный UINT в 64-битный указатель. Это самоубийство - вы пытаетесь указать на что-то, но забыли половину его местоположения! Вы ОБЯЗАТЕЛЬНО ДОЛЖНЫ взять UINT_PTR. Когда вы приводите указатель к int, поведение нормально, только если int имеет тот же размер, что и указатель. В противном случае это конец среды выполнения вашего приложения из-за нарушения прав доступа.
Изменить:
Почему компилятор считает, что приведение к большему типу - плохая идея?
R.E. выше
Как лучше всего избавиться от предупреждения? (Я не хочу отключать его.)
Решить проблему. Этот код почти наверняка будет сброшен.
Двойное приведение типа, подобное этому: (HMENU) (UINT_PTR) id избавляется от предупреждения. Почему / как?
Это происходит потому, что приведение UINT к UINT_PTR совершенно корректно - UINT_PTR - это просто интегральный тип, без потери данных.
Отключение параметра «Обнаруживать проблемы с переносимостью 64-битных версий» (Wp64) также позволяет избавиться от предупреждения. Почему Wp64 устарел? Надеть ли его?
Он устарел, потому что на самом деле я не могу вспомнить, почему. Я думаю, что это слишком легко предупреждает. Но что касается базового «Не приводить целые типы и указатели», вам определенно следует оставить его включенным.
Тип, скрывающийся за именем HMENU
, на самом деле является типом указателя .Компилятор сообщает вам, что преобразование меньшего целочисленного типа к большему типу указателя не имеет смысла, поскольку результирующее значение указателя будет «неполным», то есть битами более высокого порядка, если значение указателя будет заполнено нулями. Последнее имеет очень мало смысла с типами указателей.
В вашем конкретном случае это безопасно, поскольку это значение HMENU
на самом деле не должно быть указателем, указывающим куда-либо. Однако компилятор этого не знает, поэтому выдает предупреждение. Используйте больший тип integer в качестве промежуточного типа в приведении, и предупреждение исчезнет (вы сами это предложили), поскольку в этом случае вы выполняете два преобразования: меньшее целое число в большее целое, а затем большее целое число на указатель. Меньшее целое число к большему - это арифметическое преобразование, для которого имеет смысл заполнить старшие биты нулями (представленное значение не меняется), поэтому для него не будет предупреждений.
Почему компилятор считает плохой идеей приведение к типу большего размера?
Приведение типов разного размера обычно является проблематичной операцией, поскольку исходный тип может быть не в состоянии представляют все значения, необходимые для цели.
Как лучше всего избавиться от предупреждения? (Я не хочу его отключать.)
Я бы сказал, везде используйте HMENU
и объявите свою функцию как
HWND WebformCreate(HWND hParent, HMENU id)
Выполнение двойного приведения типов, например: (HMENU)(UINT_PTR) id избавляется от предупреждения. Почему/как?
UINT_PTR
— целочисленный тип, достаточно большой для хранения всех значений указателя, поэтому предупреждения исчезают.
HMENU
— тип указателя. Это не означает, что значение hMenu
на самом деле является указателем, но это хак, который не позволяет вам неявно смешивать, например. HMENU
и HWND
(поскольку HMENU
и HWND
похожи на struct _hMENU*
и struct _hWND *
, соответственно, которые несовместимы, тогда как UINT
были бы совместимы).