Можно ли изменить этот c-cast на reinterpret_cast?

Я пытаюсь удалить c-style cast из некоторого кода, над которым я работаю, и у меня есть опасения по поводу единственной альтернативы.

Исходный код:

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 невозможно, и это не связано с константой, C-cast должен делать reinterpret_cast в любом случае, а это значит, что базовый код должен отбрасываться, что означает, что это безопасно (пункт 3 в примечаниях). Но я хотел бы подтвердить это, прежде чем просто изменить код.

Является ли это безопасным в этом конкретном экземпляре и как это подтвердить? Если нет, то какова альтернатива?

Ответ 1

Это безопасно, потому что 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>(...).

Ответ 2

Да, это прекрасно, и для чего предназначен reinterpret_cast, т.е. подход "доверяй мне, что я знаю, что я делаю", который должен выполнять кастинг.

Ответ 3

Он может работать на вашем компьютере, с вашим компилятором и с очень специфическим набором параметров компиляции для вашего компилятора.

Вы вводите один тип указателя в другой. Это не "безопасно". Ваш код нарушает правило строгого сглаживания. Это позволяет вашему компилятору интерпретировать ваш код так, чтобы он отличался от вашего намерения. Ваш код может работать, возможно, нет. Вы вызываете поведение undefined.

Ответ 4

Нет, как правило. Стили стиля C будут стараться делать то, что правильно. Это обычно означает попытку a static_cast и только если это невозможно сделать reinterpret_cast

Взгляните на следующий код на С++

#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

Другими словами, небезопасно слепо заменять стили стиля C на reinterpret_casts.