我正在尝试从我正在处理的一些代码中删除一个c风格的演员,我担心唯一的选择。
原始代码是:
WPARAM param = (WPARAM)(GetDlgItem(IDC_WORKFLOW).m_hWnd);
this->PostMessage(WM_NEXTDLGCTL, param, TRUE);
如果我使用静态演员:
WPARAM param = static_cast<WPARAM>(GetDlgItem(IDC_WORKFLOW).m_hWnd);
this->PostMessage(WM_NEXTDLGCTL, param, TRUE);
我收到错误'static_cast':无法从'HWND'转换为'WPARAM',因为底层类型之间没有有效的转换。这让我留下了“魔鬼的选择”:
WPARAM param = reinterpret_cast<WPARAM>(GetDlgItem(IDC_WORKFLOW).m_hWnd);
this->PostMessage(WM_NEXTDLGCTL, param, TRUE);
据我了解,如果static_cast不可能,并且这与constness无关,那么无论如何C-cast必须进行reinterpret_cast,这意味着底层代码必须返回,which means this is safe (评论中的第3点)。但是我想在更改代码之前确认一下。
在此特定情况下,此播放是否安全,如何确认?如果没有,有什么替代方案?
答案 0 :(得分:4)
这是安全的,因为WPARAM
定义为:
typedef UINT_PTR WPARAM;
和_PTR后缀表示该类型足以容纳指针。
而HWND是:
typedef HANDLE HWND;
HANDLE是:
typedef void *HANDLE;
因此void *和UINT_PTR的大小始终相同。如果你将它存储在64位应用程序中并尝试在32位应用程序中读取,那么你就会遇到麻烦。
如果你仍然认为这样做是否安全,你可以搜索Visual Studio源代码(在C:\ Program Files(x86)\ Microsoft Visual Studio 8 \文件夹中),你会发现很多行reinterpret_cast<LPARAM>(...)
和reinterpret_cast<WPARAM>(...)
。
答案 1 :(得分:2)
是的,这很好,是reinterpret_cast
的目的,即“相信我,我知道我在做什么”的方法,C必须铸造。
答案 2 :(得分:1)
也许现在我们可以使用C ++ 20中的std::bit_cast
作为替代方式,这应该表现得更好。
在后台,std::bit_cast
使用std::memcpy
,我认为您也可以使用它从HWND
投射到WPARAM
答案 3 :(得分:0)
它可能适用于您的计算机,编译器以及编译器的一组非常具体的编译选项。
您正在将一种指针类型转换为另一种指针类型。那不是“安全的”。您的代码违反了严格的别名规则。这使您的编译器能够以与您的预期完全不同的方式解释您的代码。您的代码可能有效,但可能无效。您正在调用未定义的行为。
答案 4 :(得分:0)
不是一般规则。 C风格演员将尝试做正确的事。这通常意味着尝试static_cast
并且只有在执行reinterpret_cast
查看以下C ++代码
#include <stdio.h>
#include <new>
class Base
{
public:
int base;
};
class Extension
{
public:
int extension;
};
class Derived : public Base, public Extension
{
public:
int derived;
};
int main()
{
Derived* der = new Derived;
der->base = 1;
der->extension = 2;
der->derived = 3;
Extension* ext = (Extension*)der;
printf ("The value of ext->extension = %d\n",ext->extension);
ext = reinterpret_cast<Extension*>(der);
printf ("The value of ext->extension = %d\n",ext->extension);
}
结果
c:\work>test
The value of ext->extension = 2
The value of ext->extension = 1
换句话说,用reinterpret_casts盲目地替换C样式转换是不安全的。