为什么我可以使用 static_cast 与 void* 而不是与字符*

Why can I use static_cast With void* but not With char*

本文关键字:void 字符 cast 可以使 我可以 static 为什么      更新时间:2023-10-16

我知道reinterpret_cast主要用于往返char*

但我惊讶地发现static_cast可以用void*做同样的事情。例如:

auto foo "hello world"s;
auto temp = static_cast<void*>(&foo);
auto bar = static_cast<string*>(temp);

我们从使用reinterpret_castchar*而不是static_castvoid*中获得什么?这与严格的混叠问题有关吗?

一般来说,如果其中一个可以隐式转换为另一个类型,static_cast将强制转换任何两种类型。这包括算术转换、向下转换、向上转换和往返void*的转换。

也就是说,如果此强制转换有效:

void foo(A a);
B b;
foo(b);

然后,static_cast<B>(a)static_cast<A>(b)也将有效。

由于任何指针都可以隐式投射到 void* ,因此您的特殊行为。

reinterpret_cast通过重新解释值的位模式来强制转换。正如您在问题中所说,这通常是为了在不相关的指针类型之间进行转换。

是的,您可以使用两个static_cast通过 void* 在不相关的指针类型之间进行转换:

B *b;
A *a1 = static_cast<A*>(b); //compiler error
A *a2 = static_cast<A*>(static_cast<void*>(b)); //it works (evil laugh)!

但这正在扭曲规则。如果您真的需要这个,只需使用reinterpret_cast

你的问题实际上有两个部分:

  1. 我是否应该使用 static_castreinterpret_cast 来处理指向对象基础位模式的指针,而不考虑对象类型?
  2. 如果我应该使用reinterpret_castvoid*还是char*更可取来解决这种底层位模式?

static_cast:使用隐式转换和用户定义转换的组合在类型之间进行转换

在 5.2.9[expr.static.cast]13 中,标准实际上给出了以下示例:

T* p1 = new T;
const T* p2 = static_cast<const T*>(static_cast<void*>(p1));

它利用隐式强制转换:

指向任何(可选 cv 限定的(对象类型的 prvalue 指针T可以转换为指向(相同 cv 限定的(void 的 prvalue 指针。生成的指针表示与原始指针值在内存中相同的位置。如果原始指针是空指针值,则结果是目标类型的空指针值。*

但是,从类型 T 的指针到char*没有隐式强制转换。因此,完成该演员的唯一方法是使用reinterpret_cast

reinterpret_cast:通过重新解释底层位模式在类型之间进行转换

因此,在回答问题的第 1 部分时,当您转换为您希望使用底层位模式的void*char*时, 应该使用reinterpret_cast,因为它的使用向读者表示与底层位模式之间的转换。

接下来,让我们将void*char*进行比较。这两者之间的决定可能更多地依赖于应用程序。如果要将标准库函数与底层位模式一起使用,只需使用函数接受的类型:

  • void*用于cstring库中提供的mem函数
  • readwrite使用char*作为输入

值得注意的是,C++特定的库更喜欢char*来指向内存。出于兼容性原因,将内存保留为void*似乎已被保留为此处的指针。因此,如果 cstring 库函数不会用于您的底层位父级,请使用C++特定库行为来回答问题的第 2 部分:首选char*而不是void*