何时使用reinterpret_cast而不违反严格的别名规则?

o_o*_*tle 2 c++ casting reinterpret-cast

很长一段时间我都是reinterpret_cast这样使用的:

static_assert(sizeof(int) == sizeof(float));
int a = 1;
float b = *reinterpret_cast<float*>(&a); // viewed as float in binary.
Run Code Online (Sandbox Code Playgroud)

然而,当我最近回顾C++中的类型转换时,我发现当考虑严格的别名规则时,它是UB!可以优化对初始数据的不同类型(或者确切地说,非相似类型)的指针的引用。(我知道std::bit_cast在 C++20 中这是另一种方法。)

从我的角度来看,reinterpret_cast主要是用于指针类型转换。然而,考虑到禁止取消引用,我如何使用另一种类型的指针?

我浏览了何时使用reinterpret_cast,下面引用了一个答案:

需要reinterpret_cast 的一种情况是与不透明数据类型交互时。这种情况经常发生在程序员无法控制的供应商 API 中。下面是一个人为的示例,其中供应商提供了用于存储和检索任意全局数据的 API。

但是当涉及到这些API的实现时,如果要在那里使用数据,就很难避免取消对指针的引用。

看起来只有转换为另一种指针类型并返回初始指针类型才是合理的(但这有什么意义?为什么不使用初始类型或直接定义模板?)。所以我的问题是:什么时候使用reinterpret_cast而不违反该规则?有没有通用的用法?

我真的是 C++ 的新手,所以任何建议将不胜感激。

Adr*_*ica 6

当您在代码中使用 a 时reinterpret_cast,您是在告诉编译器:“我知道我在做什么 \xe2\x80\x93 只需实现转换并相信我结果可以使用。” 然后,编译器将像使用指定目标类型的任何其他对象一样使用该转换的结果。

\n

因此,如果您知道特定值是实际数据类型的地址float,那么您可以安全地将intptr_t值转换为(例如)float*并取消引用结果指针。

\n

这种使用的常见情况发生reinterprt_cast在 Windows (WinAPI) 编程中:LPARAMWindows 消息的 经常用于指向特定类型的数据结构。以下是消息处理程序的“伪示例” WM_NOTIFY

\n
BOOL OnNotify(WPARAM wParam, LPARAM lParam, LRESULT *pResult)\n{\n    NMHDR *pHdr = reinterpret_cast<NMHDR *>(lParam);\n    switch (pHdr->code) {\n        // ... do some stuff with the data in the referenced NMHDR structure\n    }\n    //...\n    *pResult = 0;\n    return TRUE;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

在这种情况下,Windows 框架“承诺”lParam收到的参数是结构的地址NMHDR,因此强制转换是安全的。(请注意,其他 C++ 强制转换不适用于此类转换:只有reinterpret_cast“C 风格”强制转换才能将整数类型转换为指针。)

\n
\n

然而,由于您在问题中提到的严格别名规则,使用任何类型的强制转换(reinterpret_cast尤其是 C 风格)进行所谓的类型双关从来都不是一个好主意。要将位(“按原样”)从 an 复制int到 a float(假设这些类型大小相同,并且您无权访问 C++20 std::bit_cast),您应该使用std::memcpy, 而不是取消引用别名指针。

\n