0
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 without and then do the reinterpret_cast to the 2 byte offset.

chriskirk
  • 761
  • 1
  • 11
  • 22
  • I believe `reinterpret_cast` is *slower* than `static_cast`. – Nawaz Jun 29 '11 at 15:10
  • 1
    @Nawaz any references for that statement? – chriskirk Jun 29 '11 at 15:17
  • 1
    @Nawaz: Really? Seems unlikely.. – Lightness Races in Orbit Jun 29 '11 at 15:20
  • Where have you got the `2` from? If it's a variable, containing the known offset of a `Uint32` member of the struct, but it'll be a different member at runtime according to some runtime property, then perhaps you could use a pointer-to-member instead. If you're reading some ASN.1-style mix of different data, that tells you the offsets of various bits of itself, then the portable way to pick up a 4 byte integer is one byte at a time, shifting and ORing. If you want "fast" you'll need to do something implementation-specific. `UInt32` looks Windows-y, but who knows. – Steve Jessop Jun 29 '11 at 15:24
  • @Nawaz: Define slower for a compile time operation. – Martin York Jun 29 '11 at 15:25
  • Why can't you just access the member? – Karl Knechtel Jun 29 '11 at 17:08
  • @Martin: hindering the optimizer. – MSalters Jun 29 '11 at 19:08
  • 1
    @MSalters: Makes no difference to the optimizer. The casts basically tell the compiler to trust the user. After that point the types are as indicated by the user the compiler/optimizer does not care if you make a mistake. – Martin York Jun 29 '11 at 21:07

4 Answers4

4

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.

Mark B
  • 95,107
  • 10
  • 109
  • 188
  • Please see my comment below. I would just access it directly however the location of the item is inside a union and I'm doing a pre-verification before doing the reinterpret_cast – chriskirk Jun 29 '11 at 17:26
1

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.

Community
  • 1
  • 1
Billy ONeal
  • 104,103
  • 58
  • 317
  • 552
  • I like your answer. Please check my edited post as you might find it of interest. – chriskirk Jun 29 '11 at 17:30
  • @chriskirk: If that's the case, no reason to `reinterpret_cast` -- just access the member in any of those 16 unions. They're going to occupy the same memory space, right? – Billy ONeal Jun 29 '11 at 18:07
0

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.

umlcat
  • 4,091
  • 3
  • 19
  • 29
0

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.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699