开发者

Safe way to reinterpret_cast raw struct at particular offset and type?

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

Struct is pragma packed 1 and contains a bunch of uint, char, short fields...

Since it's UInt32, should it first be reinterpret_cast to unsigned char* instead or does it even matter?

Also, speed is critical here and I believe reinterpret_cast is the fastest of the casts as opposed to static_cast.

EDIT: The struct is actually composed of two single-byte fields followed by a union of about 16 other structs 15 of which have the UInt32 as its first field. I do a quick check that it's not the one witho开发者_如何学编程ut and then do the reinterpret_cast to the 2 byte offset.


Can't you just access the member directly? This is undefined behavior and won't work at all on systems that enforce word alignment (which is probably not a problem given you're doing it but needs to be mentioned).

reinterpret_cast wouldn't be any faster than static_cast because they just tell the compiler how to use memory at compile time. However dynamic_cast would be slower.

There's no legal way to just treat your struct + offset as a non-char type.


reinterpret_cast and static_cast should have the same runtime -- next to zero unless numerical conversion needs to be performed. You should choose the cast to use not based on "speed", but based on correctness. If you were talking about dynamic_cast you might have a cause for argument, but both reinterpret_cast and static_cast usually lead to (at worst) a register copy (E.g. from an integer register into a floating point register). (Assuming no user defined conversion operators get into the picture, then it's a function call with all it's attendant stuff)

There is no safe way to do what you're doing. That breaks the strict aliasing rule. If you wanted to do something like this your struct would need to be in some form of union where you access the UInt32 through the union.

Finally, as already mentioned, that example will fail on any platform with alignment issues. That means you'll be fine on x86, but will not be fine on x64, for example.


You forgot to mention, that you are using a pointer to an struct, not a struct by itself, in any case, I find unnecesary to use pointer arithmetic, for a particular field of a struct. The compiler and generated code, won't be any faster for using pointer arithmetic, and would make your code more comples, unnecesarily:

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);
}

Cheers.

UPDATE1: Added "union" to example.


Since you say that the struct contains ints and shorts, I'm going to go out on a limb and answer on the assumption that this union is POD. If so then you benefit from 9.5/1:

one special guarantee is made in order to simplify the use of unions: If a POD-union contains several POD-structs that share a common initial sequence (9.2), and if an object of this POD-union type contains one of the POD-structs, it is permitted to inspect the common initial sequence of any of POD-struct members

So, assuming your structure looks like this:

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; 
};

Then you can do this:

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

If the members of the union aren't POD, then your reinterpret_cast is broken anyway, since there is no longer any guarantee that the first data member of the struct is located at offset 0 from the start of the struct.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜