Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it safe to change this c-cast to a reinterpret_cast?

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?

like image 279
deworde Avatar asked Feb 13 '14 11:02

deworde


People also ask

Is it safe to use reinterpret_cast?

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).

What is the difference between static_cast and reinterpret_cast?

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.

What is C style cast?

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.

Is reinterpret_cast portable?

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.


3 Answers

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>(...).

like image 91
marcinj Avatar answered Sep 22 '22 21:09

marcinj


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.

like image 31
Sean Avatar answered Sep 20 '22 21:09

Sean


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

like image 42
haohaolee Avatar answered Sep 22 '22 21:09

haohaolee