很长一段时间我都这样使用reinterpret_cast
:
static_assert(sizeof(int) == sizeof(float));
int a = 1;
float b = *reinterpret_cast<float*>(&a); // viewed as float in binary.
然而,当我最近回顾 C++ 中的类型转换时,我发现它在考虑严格别名规则 时是 UB!可以优化将不同类型(或确切地说,非相似类型)的指针取消引用到初始数据。 (我知道 C++20 中的 std::bit_cast
是另一种方法。)
在我看来,reinterpret_cast
主要是用来做指针类型转换的。尽管如此,考虑到取消引用被禁止,我如何使用另一种类型的指针?
我浏览过when to use reinterpret_cast ,下面引用了一个答案:
One case when reinterpret_cast is necessary is when interfacing with opaque data types. This occurs frequently in vendor APIs over which the programmer has no control. Here's a contrived example where a vendor provides an API for storing and retrieving arbitrary global data.
但是当涉及到这些 API 的实现时,如果要在那里使用数据,则很难避免取消引用指针。
似乎只有转换为另一种指针类型并返回初始指针类型是合理的(但这有什么意义?为什么不使用初始类型或直接定义模板?)。所以我的问题是:何时使用 reinterpret_cast
而不违反该规则?有什么通用的用法吗?
我真的是 C++ 的新手,所以任何建议将不胜感激。
最佳答案
当您在代码中使用 reinterpret_cast
时,您是在告诉编译器:“我知道我在做什么 – 只需实现转换并相信我,结果会好的以使用。” 然后,编译器将使用该转换的结果,就像使用指定目标类型的任何其他对象一样。
因此,如果您知道特定值是实际float
数据类型的地址,那么您可以安全地转换(比方说)intptr_t
值到 float*
并取消引用结果指针。
reinterprt_cast
的这种用法的常见情况发生在 Windows (WinAPI) 编程中:Windows 消息的 LPARAM
通常用于指向特定类型的数据结构。以下是 WM_NOTIFY
消息处理程序的“伪示例”:
BOOL OnNotify(WPARAM wParam, LPARAM lParam, LRESULT *pResult)
{
NMHDR *pHdr = reinterpret_cast<NMHDR *>(lParam);
switch (pHdr->code) {
// ... do some stuff with the data in the referenced NMHDR structure
}
//...
*pResult = 0;
return TRUE;
}
在这种情况下,Windows 框架已“ promise ”接收到的lParam
参数将 是NMHDR
结构的地址,因此 Actor 是安全的。 (请注意,其他 C++ 强制转换不适用于此类转换:只有 reinterpret_cast
或“C-Style”强制转换可以将整数类型转换为指针。)
但是,对于所谓的 type punning,使用任何类型的转换(reinterpret_cast
或 C 风格,尤其如此)从来都不是一个好主意,因为您在问题中提到了严格的别名规则。将位(“原样”)从 int
复制到 float
(假设这些类型的大小相同,并且您无权访问C++20 std::bit_cast
), 你应该使用 std::memcpy
,而不是取消引用别名指针。
关于c++ - 什么时候使用 reinterpret_cast 而不违反严格的别名规则?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72935819/