在特定偏移量和类型上重新解释原始结构的安全方法?

时间:2011-06-29 15:04:55

标签: c++ casting struct reinterpret-cast

return *reinterpret_cast<UInt32*>((reinterpret_cast<char*>(this) + 2));

struct是pragma packed 1,包含一堆uint,char,short fields ......

因为它是UInt32,它应该首先将reinterpret_cast重新解释为unsigned char *,还是甚至重要?

此外,速度至关重要,我相信reinterpret_cast是演员阵容中最快的,而不是static_cast。

编辑:结构实际上由两个单字节字段组成,后跟一个大约16个其他结构的并集,其中15个以UInt32作为其第一个字段。我快速检查一下,不是没有,然后将reinterpret_cast转换为2字节偏移量。

4 个答案:

答案 0 :(得分:4)

你不能直接访问会员吗?这是未定义的行为,并且在强制执行单词对齐的系统上根本不起作用(这可能不是问题,因为你正在这样做但需要提及)。

reinterpret_cast不会比static_cast快,因为它们只是告诉编译器如何在编译时使用内存。但是dynamic_cast会更慢。

没有合法的方法可以将struct + offset视为非char类型。

答案 1 :(得分:1)

除非需要执行数值转换,否则

reinterpret_caststatic_cast应具有相同的运行时间 - 接近零。您应该根据“速度”选择使用的强制转换,但要基于正确性。如果你在谈论dynamic_cast,你可能有一个争论的原因,但reinterpret_caststatic_cast通常会导致(最坏的情况下)寄存器副本(例如从整数寄存器到浮动点寄存器)。 (假设没有用户定义的转换操作符进入图片,那么它是一个函数调用,包含所有它的附带内容)

没有安全的方法来做你正在做的事情。这打破了strict aliasing规则。如果您想要执行此类操作,则struct需要采用某种形式的union,您可以通过该联盟访问UInt32

最后,如前所述,该示例将在任何具有对齐问题的平台上失败。这意味着你在x86上会很好,但是在x64上会不会很好。例如。

答案 2 :(得分:0)

你忘了提到,你使用指向结构的指针,而不是结构本身,在任何情况下,我发现对于结构的特定字段使用指针算法是不必要的。使用指针算法,编译器和生成的代码将不会更快,并且会使您的代码更加复杂,不必要:

struct AnyInfoStruct {
   char Name[65]; 
   char Address[65]; 
   short Whatever; 
   uint Years;
   union AExtraData { 
      int A; 
      char B; 
      double C; 
   } ExtraData
}; 

// recieves generic pointer, hidding struct fields:
void showMsg(void* AnyPtr)
{
  AnyInfoStruct* MyAnyInfo = &(static_cast<*AnyPtr>);
  cout << "Years: " << MyAnyInfo->Years << "\n";

  cout << "ExtraData.A: " << MyAnyInfo->ExtraData.A << "\n";
}

void main()
{
  AnyInfoStruct* MyAnyInfo; 

  // hide struct into a ptr
  void* AnyPtr = AnyInfoStruct;

  showMsg(MyAnyInfo);
}

干杯。

UPDATE1:在示例中添加了“union”。

答案 3 :(得分:0)

既然你说这个结构包含整数和短语,那么我就会假装这个联盟是POD,然后回答问题。如果是这样,那么您将受益于9.5 / 1:

  

提出一项特别保证   为了简化工会的使用:   如果POD-union包含多个   有共同点的POD结构   初始序列(9.2),如果是   此POD-union类型的对象包含   其中一个POD结构,它是   允许检查共同点   任何POD结构的初始序列   成员

因此,假设您的结构如下所示:

struct Foo1 { UInt32 a; other stuff; };
struct Foo2 { UInt32 b; other stuff; };
...
struct Foo15 { UInt32 o; other stuff; };
struct Bar { UInt16 p; other stuff; };

// some kind of packing pragma
struct Baz {
    char is_it_Foo;
    char something_else;
    union {
        Foo1 f1;
        Foo2 f2;
        ...
        Foo15 f15;
        Bar b;
    } u; 
};

然后你可以这样做:

Baz *baz = whatever;
if (baz->is_it_Foo) {
    UInt32 n = baz->u.f1.a;
}

如果union的成员不是POD,那么你的reinterpret_cast无论如何都会被破坏,因为不再保证结构的第一个数据成员位于从0开始的偏移0处。结构