铸造的Struct到数组 [英] Casting a Struct to an Array

查看:140
本文介绍了铸造的Struct到数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一个严格走样的问题,如将编译器造成任何优化订单的问题与此有关。

说我在结构XMFLOAT3 (不同于<一个有三个公共浮动取值href=\"https://msdn.microsoft.com/en-us/library/windows/desktop/microsoft.directx_sdk.reference.xmfloat3%28v=vs.85%29.aspx\"相对=nofollow>这个。)我想转换为浮法* 。这将降落在我的优化麻​​烦吗?

  XMFLOAT3富= {1.0F,2.0F,3.0F};
自动栏=安培; foo.x;酒吧[2] + = 5.0F;
foo.z + = 5.0F;
COUT&LT;&LT; foo.z;

我相信这将始终打印13。但是这个code:

  XMFLOAT3富= {1.0F,2.0F,3.0F};
自动栏= reinter pret_cast&LT;浮动*&GT;(安培;富);酒吧[2] + = 5.0F;
foo.z + = 5.0F;
COUT&LT;&LT; foo.z;

我相信这是合法的,因为根据的 HTTP://en.cp$p$pference.com/w/cpp/language/reinter$p$pt_cast#Type_aliasing


  

T 2是聚合型或持有上述类型作为元素或非静态成员之一的联合类型(包括递归subaggregates和载工会非静态数据成员的元素):这使得它安全地从一个结构的第一个成员,并从工会的元素的结构/联合包含它投。


是我这是正确的理解?

<子>显然,这将成为实现依赖的声明 XMFLOAT3


解决方案

reinter pret_cast XMFLOAT3 * 浮法* 是确定的,因为:

9.2 [class.mem]第20段:


  

如果一个标准的布局类对象具有任何非静态数据成员,它的地址是相同的其第一非静态数据成员的地址。否则,它的地址是相同的第一基类的地址
  子对象(如果有的话)。 [注:的可能存在,因此有必要标准的布局结构对象中未命名的填充,而不是在它的开始,实现适当的调整。 - 注完的]


这是指第一个成员的地址是结构的地址,而且也没有当您访问参与走样 *栏因为你访问一个浮动通过类型的左值浮动,这是很好的。

但铸也不必要,这是相当于第一版本

 自动栏=安培; foo.x;

这位前pression 酒吧[2] 只有OK如果有结构或更多$ P $成员之间没有填充pcisely,如果数据成员的布局是一样的数组浮动[3] ,在这种情况下,3.9.2 [basic.compound]第3段说,这是确定:


  

一个对象指针类型重新presents的有效值无论是在内存中(1.7)字节的地址或一个空指针(4.10)。如果类型的对象 T 位于地址 A ,类型的指针的 CV T * ,其值为
  地址 A 据说指向的对象,不管是如何得到的值。


在实践中有任何理由,三个相邻的相同类型的非静态数据成员不会相同奠定了一个数组(我认为安腾ABI保证),但为了安全起见,你可以添加:

  static_assert(的sizeof(XMFLOAT3)==的sizeof(浮动[3]),
     XMFLOAT3布局必须与浮动[3]兼容);

或者是偏执,或者有额外的只是后成员以Z

  static_assert(offsetof(XMFLOAT3,Y)==的sizeof(浮动)
               &功放;&安培; offsetof(XMFLOAT3,Z)==的sizeof(浮动)* 2,
     XMFLOAT3布局必须与浮动[3]兼容);


  

显然,这将成为实现依赖于XMFLOAT3的声明。


是的,它依赖于它是一个标准的布局类类型,其数据成员的顺序和类型。

This is an strict aliasing question, as in will the compiler cause any optimization order problems with this.

Say that I have three public floats in a struct XMFLOAT3 (not unlike this one.) And I want to cast to a float*. Will this land me in optimization trouble?

XMFLOAT3 foo = {1.0f, 2.0f, 3.0f};
auto bar = &foo.x;

bar[2] += 5.0f;
foo.z += 5.0f;
cout << foo.z;

I assume this will always print "13". But what about this code:

XMFLOAT3 foo = {1.0f, 2.0f, 3.0f};
auto bar = reinterpret_cast<float*>(&foo);

bar[2] += 5.0f;
foo.z += 5.0f;
cout << foo.z;

I believe this is legal because, according to http://en.cppreference.com/w/cpp/language/reinterpret_cast#Type_aliasing

T2 is an aggregate type or a union type which holds one of the aforementioned types as an element or non-static member (including, recursively, elements of subaggregates and non-static data members of the contained unions): this makes it safe to cast from the first member of a struct and from an element of a union to the struct/union that contains it.

Is my understanding of this correct?

Obviously this will become implementation dependent on the declaration of XMFLOAT3.

解决方案

The reinterpret_cast from XMFLOAT3* to float* is OK, due to:

9.2 [class.mem] paragraph 20:

If a standard-layout class object has any non-static data members, its address is the same as the address of its first non-static data member. Otherwise, its address is the same as the address of its first base class subobject (if any). [ Note: There might therefore be unnamed padding within a standard-layout struct object, but not at its beginning, as necessary to achieve appropriate alignment. — end note ]

That means the address of the first member is the address of the struct, and there's no aliasing involved when you access *bar because you're accessing a float through an lvalue of type float, which is fine.

But the cast is also unnecessary, it's equivalent to the first version:

auto bar = &foo.x;

The expression bar[2] is only OK if there is no padding between the members of the struct, or more precisely, if the layout of the data members is the same as an array float[3], in which case 3.9.2 [basic.compound] paragraph 3 says it is OK:

A valid value of an object pointer type represents either the address of a byte in memory (1.7) or a null pointer (4.10). If an object of type T is located at an address A, a pointer of type cv T* whose value is the address A is said to point to that object, regardless of how the value was obtained.

In practice there is no reason that three adjacent non-static data members of the same type would not be laid out identically to an array (and I think the Itanium ABI guarantees it), but to be safe you could add:

 static_assert(sizeof(XMFLOAT3)==sizeof(float[3]),
     "XMFLOAT3 layout must be compatible with float[3]");

Or to be paranoid, or if there are just additional members after z:

 static_assert(offsetof(XMFLOAT3, y)==sizeof(float)
               && offsetof(XMFLOAT3, z)==sizeof(float)*2,
     "XMFLOAT3 layout must be compatible with float[3]");

Obviously this will become implementation dependent on the declaration of XMFLOAT3.

Yes, it relies on it being a standard-layout class type, and on the order and type of its data members.

这篇关于铸造的Struct到数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆