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?You're casting a 32bit UINT to a 64bit pointer. That's suicide - you're trying to point to something but forgot half it's location! You absolutely MUST take a UINT_PTR. When you cast a pointer to an int, the behaviour is only OK if the int has the same size as the pointer. Else, it's the end of your application's runtime courtesy of an access violation.
Edit:
Why does the compiler think it's a bad idea to cast to a bigger type?
R.E. above
What's the best way to get rid of the warning? (I don't want to disable it.)
Fix the problem. This code will almost certainly instacrash.
Doing a double type cast like this: (HMENU)(UINT_PTR)id gets rid of the warning. Why/how?
It happens because casting a UINT to a UINT_PTR is perfectly valid- UINT_PTR is just an integral type, there's no loss of data.
Disabling "Detect 64-bit Portability Issues" (Wp64) also gets rid of the warning. Why is Wp64 deprecated? Should I have it on?
It's deprecated because, actually, I can't quite remember why. I think it warns a little too readily. But for the basic "Don't cast integral types and pointers", you should definitely leave it on.
The type that's hiding behind the HMENU
name is actually a pointer type. The compiler is telling you that casing a smaller integer type to a larger pointer type makes no sense, since the resultant pointer value will be "incomplete", i.e. the higher order bits if the pointer value will be filled with zeros. The latter makes very little sense with pointer types.
In your particular case this is safe, since this HMENU
value is not really supposed to be a pointer that points anywhere. However, the compiler does not know that, which is why it issues a warning. Use a larger integer type as an intermediate type in the cast and the warning shall go away (you suggested that yourself), since in this case you are doing two casts: smaller integer to a larger integer, and then larger integer to a pointer. Smaller integer to a larger integer is an arithmetic cast, for which it makes perfect sense to fill the higher-order bits with zeros (the represented value does not change), so there will be no warning for it.
Why does the compiler think it's a bad idea to cast to a bigger type?
Casting between types of different size is generally a problematic operation, because the source type might not be able to represent all values needed for the target.
What's the best way to get rid of the warning? (I don't want to disable it.)
I'd say, use HMENU
everywhere and declare your function as
HWND WebformCreate(HWND hParent, HMENU id)
Doing a double type cast like this: (HMENU)(UINT_PTR)id gets rid of the warning. Why/how?
UINT_PTR
is an integer type large enough to hold all pointer values, therefore the warnings go away.
HMENU
is a pointer type. This doesn't mean a value of a hMenu
is actually a pointer, but this is a hack that disallows you to implicitly mix eg. HMENU
and HWND
(because HMENU
and HWND
are something like struct _hMENU*
and struct _hWND*
, respectively, which are not compatible, whereas UINT
s would be).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With