铸造的Struct到数组 [英] Casting a Struct to an Array
问题描述
这是一个严格走样的问题,如将编译器造成任何优化订单的问题与此有关。
说我在结构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
,类型的指针的 CVT *
,其值为
地址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
float
s in astruct XMFLOAT3
(not unlike this one.) And I want to cast to afloat*
. 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
fromXMFLOAT3*
tofloat*
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 afloat
through an lvalue of typefloat
, 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 arrayfloat[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 addressA
, a pointer of type cvT*
whose value is the addressA
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屋!