安全地转换struct指针

时间:2012-09-22 23:53:28

标签: c++ casting struct

我一直认为在向结构*转换void *之后检查指针是避免无效转换的有效方法。像

这样的东西
MyStructOne* pStructOne = (MyStructOne*)someVoidPointer;
if(!pStructOne)
   return 0;

似乎不是这种情况,因为我可以将相同的数据转换为两个不同的结构并获得相同的有效地址。然后程序很乐意使用随处的随机数据填充我的struct字段。

什么是构建struct指针的安全方法?

我无法使用dynamic_cast<>因为它不是一个班级。

感谢您的帮助!

8 个答案:

答案 0 :(得分:2)

如果您对结构布局有任何控制,则可以在每个结构的前面放置自己的类型枚举以验证类型。这适用于C和C ++。

如果您不能使用枚举,因为并非所有类型都是提前知道的,您可以使用GUID。或指向静态变量或每个结构唯一的成员的指针。

答案 1 :(得分:1)

只要具有虚拟方法,就可以将dynamic_cast与结构或类一起使用。我建议你重新设计更广泛的系统,以便在任何地方都没有void*。这是非常糟糕的练习/设计。

答案 2 :(得分:1)

没有一个。坦率地说,不可能有。

struct只是编译器以特定语义方式处理下一个sizeof()字节的指令 - 仅此而已。

您可以将任何指针转换为任何指针 - 所有更改都是编译器解释内容的方式。

使用dynamic_cast<>是唯一的方法,但它会调用RTTI(运行类型类型信息)来考虑分配的潜在合法性。是的,它不再是reinterpret_cast<>

答案 3 :(得分:1)

听起来你想要确保作为void*传递给你的函数的对象真的是你期望的类型。最好的方法是使用MyStructOne*而不是void*声明函数原型,并让编译器进行类型检查。

如果你真的想要做一些更动态的事情(因为可以将不同类型的对象传递给你的函数),你需要启用RTTI。这将允许您询问传入的对象并询问它是什么类型。

答案 4 :(得分:1)

一般来说,没有“安全的投射方式”,因为投射指针本质上是一个不安全的程序。 Casting说你比类型系统更清楚,所以在开始构建指针之后你不能指望类型系统有任何帮助。

在C ++中,你绝不应该使用C风格的强制转换(如(T) x),而是使用C ++强制转换。现在,您可以通过一些简单的规则来确定是否可以转换指针或引用:

  • 如果const_cast处于不良方向并修改对象,则必须确保该对象实际上是可变的。

  • 您只能在多态层次结构中使用static_cast指针或引用,或者从/到无效指针。您必须确保对象的动态类型是强制转换目标的子类型,或者在void指针的情况下,指针是正确类型的对象的地址。

  • reinterpret_cast应仅用于char *类型(可能是signedunsigned),或用于将指针转换为{和{ {1}}。

在每种情况下,您的责任是确保有问题的指针或引用引用您在演员表中声明的类型的对象。没有任何其他人可以帮您验证这一点。

答案 5 :(得分:1)

您正在使用的(C风格)转换是编译时操作 - 也就是说编译器生成指令以修改指向一个事物的指针,使其指向另一个事物。

使用继承关系,这只是指针的加法或减法。

对于代码,编译器会精确地生成 no code 。演员表只是告诉编译器你知道你在做什么。

编译器不会生成任何检查操作有效性的代码。如果someVoidPointer为空,则在投射后pStructOnedynamic_cast<>()。 \

使用{{1}}并不验证正在进行渲染的东西实际上是一个对象 - 它只是告诉您具有RTTI的对象是(或可以转换为)您期望的类型。如果它不是一个开始的对象,你很可能会崩溃。

答案 6 :(得分:0)

  

什么是构建struct指针的安全方法?

首先,尽量避免需要来执行此操作。如果您不想包含其标题,请使用结构的前向声明。通常,如果函数可以使用多个类型的数据,则只需要从签名中隐藏数据类型。类似这样的示例是消息传递系统,您希望能够传递任意数据。发送者和接收者知道他们期望什么类型,但消息系统本身不需要知道。

假设您没有其他选择,请使用boost::any。这本质上是一种类型安全的void*;尝试将其转换为错误的类型将引发异常。请注意,这需要RTTI才能工作(您通常应该可以使用它)。

请注意,如果可以使用固定的,有限的一组可能类型,boost::variant是可能的。

答案 7 :(得分:0)

由于您必须使用void*,因此您的选项是:

  1. 创建一个包含虚拟析构函数(和/或其他虚拟方法)的基类,并在libev接口上独占使用。包装libev接口以强制执行此操作,并仅使用C ++代码中的包装器。然后,在里面你的C ++代码中,你可以dynamic_cast你的基类。

  2. 接受您没有关于void*真正指向的类型的任何运行时信息,只是构建代码以便始终静态地知道。也就是说,确保首先转换为正确的类型。

  3. 使用void*来存储一个简单的标记/ cookie / id结构,并使用它来查找你的真实结构或其他 - 这实际上只是#1的更手动版本,并且引发额外的间接引导。


  4. 直接回答

      

    什么是构建struct指针的安全方法?

    是:

      

    转换为正确的类型,或者您知道与布局兼容的类型。

    没有任何替代方法可以确定静态正确的类型。你可能会将{em>某些作为void*传递给你,所以当你得到void*时,你应该能够知道它是什么类型。