reinterpret_cast<char *> 是唯一合法的 reinterpret_cast 使用方式吗?

12

我最近了解到C++标准包含“严格别名规则”,禁止通过不同类型的变量引用相同的内存位置。

但是,该标准允许char类型合法地别名任何其他类型。这是否意味着reinterpret_cast只能合法地用于将类型转换为char *char &

我认为严格别名允许在继承层次结构中的类型之间进行转换,但我认为这些情况通常会使用dynamic_cast<>?

谢谢

3个回答

11
有许多不同的用途可以使用 reinterpret_cast。在cppreference页面上列出了11种不同的情况。
我猜你只是询问第5和第6种情况:将T *转换为U *,以及将T转换为U &
在这些情况下,只要没有对齐违规,转换就是合法的。如果您通过结果表达式读取或写入内容,则会出现严格别名问题。
您在第一段中对严格别名规则的总结过于简单化,在一般情况下,U有几种合法类型。同样的cppreference页面提供了一个情况列表;您可以在C++标准草案中阅读规则的确切文本。

4
重新解释却无法利用不同的解释有什么用处呢? - Noein
@noein,这个问题对于评论来说太宽泛了。也许你可以发一个新的问题。 - M.M
@M.M:你能否举个例子说明为什么读取也会违反/UB。如果我们有一个只读缓冲区,我们根据二进制格式(int、float、bit)使用reinterpret_cast,那么即使存储缓冲区是只读的,这仍然不允许吗? - user179156
@user179156,我回答中提供的cppreference链接在“类型别名”部分解释了严格别名规则。这适用于读写操作。 - M.M
@M.M:谢谢,是的,我理解它也涉及到读取,但我不明白其原理,请问您能否提供任何代码片段或示例,说明何时会出错/未定义? - user179156

8

还有其他有用的reinterpret_cast用法。

指针转整数类型

是的,有时候想要将指针的值存储在整数类型中。

使用C++风格的转换唯一的方法是使用reinterpret_cast

例如:

auto pointerValue = reinterpret_cast<std::uintptr_t>(pointer);

将对象存储在原始内存块中

有时,您想要将数据存储在堆栈上,但稍后初始化。使用动态分配和指针不能使用堆栈。std::aligned_storage作为原始的对齐内存块非常出色。

struct MyStruct {
    int n;
    std::string s;
};

// allocated on automatic storage
std::aligned_storage<sizeof(MyStruct), alignof(MyStruct)>::type storage;

// actually initialize the object
new (&storage) MyStruct;

// using the object
reinterpret_cast<MyStruct*>(&storage)->n = 42;

我相信还有很多其他用途我不知道,但这些是我已经使用过的。


注意:也可以先形成指针,例如 auto *p = reinterpret_cast<MyStruct *>(&storage); new(&storage) MyStruct; p->n = 42; - M.M
@M.M 或者,你可以使用 auto* p = new(&storage) MyStruct; 来避免强制转换。 - T.C.
@T.C. 好的,这个的目的是为了说明reinterpret_cast的合法用途。 - M.M

6
您可以使用reinterpret_cast将指针类型转换为整数类型:
char* ptr = /* ... */
uintptr_t ptrInt = reinterpret_cast<uintptr_t>(ptr);

你获得的特定整数值在不同平台上可能不具备可移植性,但这是一种安全且定义清晰的操作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接