Questions regarding “warning C4312: 'type cast'”

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:

  1. Why does the compiler think it's a bad idea to cast to a bigger type?
  2. What's the best way to get rid of the warning? (I don't want to disable it.)
  3. Doing a double type cast like this: (HMENU)(UINT_PTR)id gets rid of the warning. Why/how?
  4. Disabling "Detect 64-bit Portability Issues" (Wp64) also gets rid of the warning. Why is Wp64 deprecated? Should I have it on?
8
задан Tobbe 25 August 2010 в 20:14
поделиться

3 ответа

Вы преобразуете 32-битный UINT в 64-битный указатель. Это самоубийство - вы пытаетесь указать на что-то, но забыли половину его местоположения! Вы ОБЯЗАТЕЛЬНО ДОЛЖНЫ взять UINT_PTR. Когда вы приводите указатель к int, поведение нормально, только если int имеет тот же размер, что и указатель. В противном случае это конец среды выполнения вашего приложения из-за нарушения прав доступа.

Изменить:
Почему компилятор считает, что приведение к большему типу - плохая идея?
R.E. выше

Как лучше всего избавиться от предупреждения? (Я не хочу отключать его.)
Решить проблему. Этот код почти наверняка будет сброшен.

Двойное приведение типа, подобное этому: (HMENU) (UINT_PTR) id избавляется от предупреждения. Почему / как?
Это происходит потому, что приведение UINT к UINT_PTR совершенно корректно - UINT_PTR - это просто интегральный тип, без потери данных.

Отключение параметра «Обнаруживать проблемы с переносимостью 64-битных версий» (Wp64) также позволяет избавиться от предупреждения. Почему Wp64 устарел? Надеть ли его?
Он устарел, потому что на самом деле я не могу вспомнить, почему. Я думаю, что это слишком легко предупреждает. Но что касается базового «Не приводить целые типы и указатели», вам определенно следует оставить его включенным.

4
ответ дан 5 December 2019 в 08:21
поделиться

Тип, скрывающийся за именем HMENU , на самом деле является типом указателя .Компилятор сообщает вам, что преобразование меньшего целочисленного типа к большему типу указателя не имеет смысла, поскольку результирующее значение указателя будет «неполным», то есть битами более высокого порядка, если значение указателя будет заполнено нулями. Последнее имеет очень мало смысла с типами указателей.

В вашем конкретном случае это безопасно, поскольку это значение HMENU на самом деле не должно быть указателем, указывающим куда-либо. Однако компилятор этого не знает, поэтому выдает предупреждение. Используйте больший тип integer в качестве промежуточного типа в приведении, и предупреждение исчезнет (вы сами это предложили), поскольку в этом случае вы выполняете два преобразования: меньшее целое число в большее целое, а затем большее целое число на указатель. Меньшее целое число к большему - это арифметическое преобразование, для которого имеет смысл заполнить старшие биты нулями (представленное значение не меняется), поэтому для него не будет предупреждений.

14
ответ дан 5 December 2019 в 08:21
поделиться

Почему компилятор считает плохой идеей приведение к типу большего размера?

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

Как лучше всего избавиться от предупреждения? (Я не хочу его отключать.)

Я бы сказал, везде используйте HMENU и объявите свою функцию как

HWND WebformCreate(HWND hParent, HMENU id)

Выполнение двойного приведения типов, например: (HMENU)(UINT_PTR) id избавляется от предупреждения. Почему/как?

UINT_PTR — целочисленный тип, достаточно большой для хранения всех значений указателя, поэтому предупреждения исчезают.

HMENU — тип указателя. Это не означает, что значение hMenu на самом деле является указателем, но это хак, который не позволяет вам неявно смешивать, например. HMENU и HWND (поскольку HMENU и HWND похожи на struct _hMENU* и struct _hWND *, соответственно, которые несовместимы, тогда как UINT были бы совместимы).

2
ответ дан 5 December 2019 в 08:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: