在特定偏移量和类型处reinterpret_cast原始结构的安全方法?

发布于 2024-11-17 23:51:10 字数 424 浏览 1 评论 0原文

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

Struct 是 pragma 打包的 1 并包含一堆 uint、char、short 字段...

既然它是 UInt32,是否应该首先将它reinterpret_cast 为 unsigned char* 或者它甚至重要?

另外,速度在这里至关重要,我相信与 static_cast 相比,reinterpret_cast 是最快的转换。

编辑:该结构实际​​上由两个单字节字段组成,后跟大约 16 个其他结构的联合,其中 15 个将 UInt32 作为其第一个字段。我快速检查了一下,确定它不是没有的,然后对 2 字节偏移量进行reinterpret_cast。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

半世蒼涼 2024-11-24 23:51:10

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

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

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

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.

慢慢从新开始 2024-11-24 23:51:10

reinterpret_caststatic_cast 应具有相同的运行时间 - 接近于零,除非需要执行数值转换。您应该选择要使用的演员表,而不是基于“速度”,而是基于正确性。如果您正在谈论dynamic_cast,您可能会有争论的理由,但是reinterpret_caststatic_cast通常都会导致(最坏的情况)寄存器副本(例如从整数寄存器到浮点寄存器)。 (假设没有用户定义的转换运算符进入图片,那么它是一个函数调用及其所有伴随的东西)

没有安全的方法来完成你正在做的事情。这违反了严格别名规则。如果您想做这样的事情,您的 struct 需要采用某种形式的 union ,您可以通过 union 访问 UInt32

最后,如前所述,该示例在任何存在对齐问题的平台上都会失败。这意味着您可以在 x86 上正常工作,但在 x64 上就不行了。

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.

圈圈圆圆圈圈 2024-11-24 23:51:10

您忘记提及,您使用的是指向结构的指针,而不是结构本身,无论如何,我发现对于结构的特定字段没有必要使用指针算术。使用指针算术的编译器和生成的代码不会更快,并且会使您的代码不必要地更加复杂:

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”。

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.

送你一个梦 2024-11-24 23:51:10

既然你说结构体包含整数和短裤,我将冒险并假设这个联合是 POD 来回答。如果是这样,那么您将受益于 9.5/1:

一项特别保证是在
为了简化联合的使用:
如果一个 POD 联合包含多个
共享共同点的 POD 结构
初始序列(9.2),并且如果
该 POD 联合类型的对象包含
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;
}

如果联合的成员不是 POD,那么你的 reinterpret_cast 无论如何都会被破坏,因为不再有任何保证结构体的第一个数据成员位于距结构体开头的偏移量 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文