c++ - 什么时候使用 reinterpret_cast 而不违反严格的别名规则?

标签 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.

然而,当我最近回顾 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/

相关文章:

c++ - qDebug() 线程安全吗?

java - 双整数转换困惑

c++ - 如何通过引用或指针将 `int` 和 `unsigned int` 成员传递给同一个函数?

C# 类型转换问题

c++ - 在 C++ 中将字符数组转换为 POD 数组

c++ - 为什么下面的代码没有断言?

C++:wikibook 中关于重载指针/引用相关运算符的代码无法编译

c++ - Pthread 和 void* 尝试取消引用通用指针

c++ - 这是reinterpret_cast 的合法使用吗?如果不是,我该怎么做?

c++ - 使用Boost Bind与std::Transform