Это код, который у меня есть:
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);
}
Это предупреждение, которое я получаю:
warning C4312: 'type cast' : conversion from 'UINT' to 'HMENU' of greater size
Вот вопросы, которые у меня есть:
- Почему компилятор считает, что приводить к большему типу - плохая идея?
- Как лучше всего избавиться от предупреждения? (Я не хочу отключать его.)
- Выполнение двойного приведения типа следующим образом:
(HMENU)(UINT_PTR)id
избавляется от предупреждения. Почему как? - Отключение функции «Обнаружение проблем с переносимостью 64-разрядной версии» (Wp64) также избавляет от предупреждения. Почему Wp64 устарел? Я должен его включить?
3 ответа
Вы преобразуете 32-битный UINT в 64-битный указатель. Это самоубийство - вы пытаетесь указать на что-то, но забыли половину его местоположения! Вы ОБЯЗАТЕЛЬНО ДОЛЖНЫ взять UINT_PTR. Когда вы приводите указатель к int, поведение нормально, только если int имеет тот же размер, что и указатель. В противном случае это конец среды выполнения вашего приложения из-за нарушения прав доступа.
Изменить:
Почему компилятор считает, что приведение к большему типу - плохая идея?
R.E. выше
Как лучше всего избавиться от предупреждения? (Я не хочу отключать его.)
Решить проблему. Этот код почти наверняка будет сброшен.
Выполнение двойного приведения типа, например: (HMENU) (UINT_PTR) id избавляется от предупреждения. Почему / как?
Это происходит потому, что приведение UINT к UINT_PTR совершенно корректно - UINT_PTR - это просто интегральный тип, без потери данных.
Отключение функции «Обнаружение проблем с переносимостью 64-разрядной версии» (Wp64) также избавляет от предупреждения. Почему Wp64 устарел? Надеть его?
Он устарел, потому что на самом деле я не могу вспомнить, почему. Я думаю, что это слишком легко предупреждает. Но что касается базового «Не приводить целые типы и указатели», вам определенно следует оставить его включенным.
WS_CHILD
, вы должны передать идентификатор дочернего окна, приведенного к типу HMENU
. Вот как это работает в WinAPI. Это не «ручка меню». Это было бы «дескриптором меню», если бы окна не были WS_CHILD
.
Тип, скрывающийся за именем HMENU
, на самом деле является типом указателя . Компилятор сообщает вам, что преобразование меньшего целочисленного типа в более крупный тип указателя не имеет смысла, поскольку результирующее значение указателя будет "неполным", то есть битами более высокого порядка. если значение указателя будет заполнено нулями. Последнее имеет очень мало смысла с типами указателей.
В вашем конкретном случае это безопасно, поскольку это значение HMENU
на самом деле не должно быть указателем, указывающим куда-либо. Однако компилятор этого не знает, поэтому выдает предупреждение. Используйте более крупный целочисленный тип в качестве промежуточного типа в приведении, и предупреждение исчезнет (вы сами это предложили), поскольку в этом случае вы выполняете два приведения: меньшее целое число к большему целому и затем большее целое число на указатель. Меньшее целое число к большему - это арифметическое преобразование, для которого имеет смысл заполнить старшие биты нулями (представленное значение не меняется), поэтому для него не будет предупреждений. .
Почему компилятор считает, что приводить к большему типу - плохая идея?
Преобразование между типами разного размера обычно является проблематичной операцией, потому что исходный тип может быть не в состоянии представить все значения, необходимые для целевого объекта.
Как лучше всего избавиться от предупреждения? (Я не хочу отключать его.)
Я бы сказал, используйте HMENU
везде и объявите свою функцию как
HWND WebformCreate(HWND hParent, HMENU id)
Выполнение двойного приведения типа, например: (HMENU) (UINT_PTR) id избавляется от предупреждения. Почему как?
UINT_PTR
- это целочисленный тип, достаточно большой для хранения всех значений указателя, поэтому предупреждения исчезают.
HMENU
- это тип указателя. Это не означает, что значение hMenu
на самом деле является указателем, но это уловка, которая запрещает вам неявно смешивать, например. HMENU
и HWND
(потому что HMENU
и HWND
похожи на struct _hMENU*
и struct _hWND*
соответственно, которые несовместимы, тогда как UINT
s будет).
Похожие вопросы
Новые вопросы
c++
C++ — это язык программирования общего назначения. Изначально он разрабатывался как расширение C и имел аналогичный синтаксис, но теперь это совершенно другой язык. Используйте этот тег для вопросов о коде, который будет скомпилирован с помощью компилятора C++. Используйте тег версии для вопросов, связанных с конкретной стандартной версией [C++11], [C++14], [C++17], [C++20] или [C++23]. и т.д.