C++ 将此c-cast更改为reinterpret_cast安全吗?

C++ 将此c-cast更改为reinterpret_cast安全吗?,c++,winapi,casting,reinterpret-cast,C++,Winapi,Casting,Reinterpret Cast,我正试图从我正在编写的一些代码中删除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->Po

我正试图从我正在编写的一些代码中删除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);
WPARAM param=static_cast(GetDlgItem(IDC_工作流).m_hWnd);
此->PostMessage(WM_NEXTDLGCTL,param,TRUE);
我得到错误“static_cast”:无法从“HWND”转换为“WPARAM”,因为底层类型之间没有有效的转换。这让我有了“魔鬼的选择”:

WPARAM param=reinterpret_cast(GetDlgItem(IDC_工作流).m_hWnd);
此->PostMessage(WM_NEXTDLGCTL,param,TRUE);
据我所知,如果静态转换是不可能的,并且这与constness无关,那么C-cast无论如何都必须重新解释转换,这意味着底层代码必须向后转换(备注中的第3点)。但我想在更改代码之前确认一下


在这种特定情况下,此强制转换安全吗?我如何确认这一点?如果没有,还有什么选择呢?

是的,这很好,并且是
重新解释cast
的目的,即C必须采用的“相信我,我知道我在做什么”方法。

这是安全的,因为
WPARAM
被定义为:

typedef UINT_PTR            WPARAM;
和PTR后缀表示类型足够大,可以容纳指针

而HWND是:

 typedef HANDLE HWND;
其中句柄为:

typedef void *HANDLE;
所以void*和UINT_PTR的大小总是相同的。若您将其存储在64位应用程序中,并尝试在32位应用程序中读取,那个么您将遇到麻烦


如果你仍然担心这样做是否安全,你可以搜索Visual Studio源代码(在C:\Program Files(x86)\Microsoft Visual Studio 8\文件夹中),你会发现很多行带有
reinterpret\u cast(…)
reinterpret\u cast(…)

它可以在你的计算机上运行,使用你的编译器,并为编译器提供了一组非常特定的编译选项


您正在将一种指针类型转换为另一种指针类型。这不是“安全的”。您的代码违反了严格的别名规则。这使编译器能够以与预期截然不同的方式解释代码。您的代码可能会工作,但可能不会。您正在调用未定义的行为。

一般来说,否。C风格演员将尝试做正确的事情。这通常意味着尝试一个
静态施法
,并且只有在无法进行
重新解释施法

看看下面的C++代码< /P>

#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样式转换是不安全的。

也许现在我们可以使用C++20中的
std::bit\u cast
作为替代方法,这应该表现得更好


在引擎盖下,
std::bit_cast
使用
std::memcpy
,我认为您也可以使用它从
HWND
转换到
WPARAM

是的,它是安全的,但是您可以继续使用C风格的cast,这在Windows API/MFC代码和IMO中很常见,更易于阅读。就像将整数类型强制转换为
void*
@MichaelFoukarakis WPARAM一样安全,它保证与指针的宽度相同,因此没有问题here@dsi我不喜欢使用C风格,因为它隐藏了你正在做的坏事,但是谢谢你指出这是我正在使用的代码库中的一种常见模式。@dsi顺便问一下,你能回答一下吗?如果找不到比这更好的答案,这对任何寻找这类问题的人来说都是“足够好”的。尽管如此,在这个特定的例子中,正如其他答案所说,这是实现所需结果的唯一途径。而且,这并不是未定义的。该行为对于基本的“从X到X的转换”、“从X到X的转换”有很好的定义,这就是reinterpret_cast的目的。实际上,使用WPARAM而不使用手柄是一个完全不同的问题,这就是我提出这个问题的原因。谢谢,这是一个很好的回答,对于一般情况,但我知道我称之为“魔鬼选项”的风险,我问的是这个具体情况,所以我不是盲目的。你可以安全地将64位HWND存储在32位类型中。查看是否定义了
STRICT
,然后
HWND
struct HWND.*
的类型定义,而不是
HANDLE
/
void*
@RemyLebeau是,但它仍然是一个指针值,没有人取消对HWND的引用。整个DECLARE_句柄只是向windows句柄添加一些typesafety。
#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