I'm trying to remove a c-style cast from some code I'm working on, and I have concerns about the only alternative.
The original code was:
WPARAM param = (WPARAM)(GetDlgItem(IDC_WORKFLOW).m_hWnd);
this->PostMessage(WM_NEXTDLGCTL, param, TRUE);
If I use a static cast:
WPARAM param = static_cast<WPARAM>(GetDlgItem(IDC_WORKFLOW).m_hWnd);
this->PostMessage(WM_NEXTDLGCTL, param, TRUE);
I get the error, 'static_cast' : cannot convert from 'HWND' to 'WPARAM', because there's no valid conversion between the underlying types. This leaves me with "the devil's option":
WPARAM param = reinterpret_cast<WPARAM>(GetDlgItem(IDC_WORKFLOW).m_hWnd);
this->PostMessage(WM_NEXTDLGCTL, param, TRUE);
As I understand it, if a static_cast is impossible, and this isn't related to constness, the C-cast must be doing a reinterpret_cast anyway, which means that the underlying code must be casting back, which means this is safe (point 3 in remarks). But I'd like to confirm this, before just changing the code.
Is this cast safe in this specific instance, and how do I confirm this? If not, what is the alternative?
reinterpret_cast is a very special and dangerous type of casting operator. And is suggested to use it using proper data type i.e., (pointer data type should be same as original data type).
static_cast only allows conversions like int to float or base class pointer to derived class pointer. reinterpret_cast allows anything, that's usually a dangerous thing and normally reinterpret_cast is rarely used, tipically to convert pointers to/from integers or to allow some kind of low level memory manipulation.
C-style casts can be used to convert any type into any other type, potentially with unsafe results (such as casting an integer into a pointer type). (<type>)<value> This example casts an int to a double for the purpose of avoiding truncation due to integer division: double result = (double)4/5; Popular pages.
Anyway, the consequence of this is, that reinterpret_cast<> is portable as long as you do not rely on the byte order in any way. Your example code does not rely on byte order, it treats all bytes the same (setting them to zero), so that code is portable.
It is safe, because WPARAM
is defined as:
typedef UINT_PTR WPARAM;
and _PTR suffix means the type is big enough to hold a pointer.
while HWND is:
typedef HANDLE HWND;
where HANDLE is:
typedef void *HANDLE;
so size of void* and UINT_PTR are always the same. If you would store it in 64bit application and try read in 32 bit application, then you would get in trouble.
if you are still concenred if that is safe to do such casts, you can search Visual Studio sources (in C:\Program Files (x86)\Microsoft Visual Studio 8\ folder), and you will find lots of lines with reinterpret_cast<LPARAM>(...)
and reinterpret_cast<WPARAM>(...)
.
Yes, this is fine, and is what reinterpret_cast
is intended for, ie the "trust me I know what I'm doing" approach that C has to casting.
maybe now we can use std::bit_cast
from C++20 as an alternative way, which should be more well-behaved.
under the hood, std::bit_cast
uses std::memcpy
, which I think you can also use to cast from HWND
to WPARAM
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