将void指针转换为特定类型指针时,哪个转换符号更好,static_cast还是reinterpret_cast?

时间:2011-02-16 07:22:26

标签: c++ casting

  

可能重复:
  Should I use static_cast or reinterpret_cast when casting a void* to whatever

在这个程序中,我有void *作为参数,并希望将其强制转换为特定类型。但我不知道使用哪种“铸造符号”。 static_castreinterpret_cast都有效。哪一个更好?标准C ++推荐哪一个?

typedef struct
{
    int a;
}A, *PA;

int foo(void* a)                // the real type of a is A*
{
    A* pA = static_cast<A*>(a); // or A* pA = reinterpret_cast<A*>(a);?
    return pA->a;
}

在这里,是

A* pA = static_cast<A*>(a);

A* pA = reinterpret_cast<A*>(a);

更合适吗?

6 个答案:

答案 0 :(得分:48)

static_cast更适合将void*转换为其他类型的指针。

static_cast是在两种类型之间进行自然,直观的转换时的选择,不一定保证在运行时工作。例如,您可以使用static_cast将基类指针转换为派生类指针,这是一种在某些情况下有意义但在运行时才能验证的转换。同样,您可以使用static_castint转换为char,这是明确定义的,但在执行时可能会导致精度损失。

另一方面,

reinterpret_cast是一个转换操作符,用于执行从根本上说不安全或不可移植的转换。例如,您可以使用reinterpret_castvoid *转换为int,如果您的系统恰好有sizeof (void*)sizeof (int),这将正常工作。您还可以使用reinterpret_castfloat*转换为int*,反之亦然,这是特定于平台的,因为float和{{1}的特定表示形式我们不保证彼此有任何共同之处。

简而言之,如果您发现自己正在进行转换,其中转换具有逻辑意义,但可能不一定在运行时成功,请避免使用intreinterpret_cast是一个很好的选择,如果你有一些预先知道演员阵容将在运行时工作,并与编译器通信“我知道这可能不起作用,但至少它是有道理的,我有一个理由相信它会在运行时正确地做正确的事。“然后,编译器可以检查转换是否在相关类型之间,如果不是这种情况则报告编译时错误。使用static_cast执行指针转换可以完全绕过编译时安全检查。

在某些情况下,您可能希望使用reinterpret_cast而不是dynamic_cast,但这些情况主要涉及类层次结构中的强制转换,并且(很少)直接关注static_cast

至于哪一个更符合规范,既没有被过度提及为“正确使用”(或者至少,我不记得其中一个被这样提到。)但是,我认为规范希望您使用void*而不是static_cast。例如,使用C样式转换时,如

reinterpret_cast

尝试的投射操作符的顺序总是尝试在A* ptr = (A*) myVoidPointer; 之前使用static_cast,这是您想要的行为,因为reinterpret_cast不能保证是可移植的。

答案 1 :(得分:1)

使用static_cast。只有极少数情况下,在没有其他办法的情况下才使用reinterpret_cast

答案 2 :(得分:0)

您可能通过隐式转化获得了void*,因此您应该使用static_cast,因为它最接近隐式转化。

答案 3 :(得分:0)

如果要沿着类层次结构进行转换,请使用dynamic_cast - 它会检查以确保实际对象与您要转换的类型兼容。

答案 4 :(得分:-1)

都不是。为什么你首先将指针传递给void?在C中它很常见,因为缺少替代方案,但在C ++中,几乎永远没有理由做任何类似的事情。

编辑:@Dan O提高了使用强制转换来最小化生成代码的可能性。对于任何不太了解他所谈论内容的人,请考虑std::vector之类的内容 - 当您定义(例如)std::vector<A *>std::vector<B *>时,您通常会结束虽然两者都只是存储指针,但每个代码都有完全独立的代码,因此它们可以共享相同的代码。可以通过定义仅容纳void * s的容器来解决这个问题,并在从容器中检索项目时转换回正确的类型。

首先,这通常是最好的过早优化(并且通常会变成悲观)。尽管如此,有时候它才有意义。但是,当它执行时,您希望将转换限制为一个位置,但是为{-1}}的伪通用容器创建模板化前端:

void *

现在,我们现在有一个演员阵容。是的,要直接回答原始问题,template <class T> pointer_container { std::vector <void *> data; public: T *operator[](size_t index) { return static_cast<T *>(data[index]); } }; 是适用于此类情况的正确答案。

回到MS-DOS时代(例如)这样的代码相当常见。然而,今天,这种代码风格毫无意义。

现在,OP已经表示他已经坚持使用固定接口,实现它是他的职责。我不知道他的工作地点或与谁合作,而且我还没有看到其他代码可以使用,所以我不能说确定他们是什么“做的设计很差,应该改变。 OTOH,根据我过去的经验,我猜这种情况的概率至少 99%。因此,我坚持原来的答案。发布的答案刚刚说了“static_cast”,没有任何关于避免演员阵容的答案是真正无益的。虽然几乎不可能无法避免演员 ,但只是假设它是合理的错误的反应和错误答案。

我会更进一步:如果关于投射的问题未能提供关于为什么投射是不可避免的证据,那么任何人都应该认为“好”的建议是建议消除完全铸造。它可能(在极少数情况下)证明无法避免演员阵容 - 但这绝对是例外,而不是规则。

答案 5 :(得分:-1)

reinterpret_cast会强制将void*转换为目标数据类型。它不保证任何安全性,您的程序可能会崩溃,因为底层对象可能是任何东西。

对于前者,您可以将myclass*类型转换为void*,然后使用reinterpret_cast将其转换为可能具有完全不同布局的yourclass*

所以更好,建议使用static_cast