看看这个片段:
struct S {
float x, y, z;
};
void fn() {
S s = { 0, 0, 0 };
float *p = &s.x;
p += 2; // 1.
if constexpr(sizeof(S)==sizeof(float)*3) { // if S has no padding
float t = *p; // 2.
s.z = 1;
float z = *p; // 3.
}
}
我的问题是:
- Is
p += 2;
布? (IE。,p
被感动了two超出自的元素s.x
,所以它超出了&s.x+1
)
- 在这里,我们知道
S
没有填充,是float t = *p;
布?或者它的定义是否明确,即t
应包含的值s.z
?
- 优化器可以优化访问吗
p
at float z = *p;
?我的意思是,是否允许z
是 0? (是否允许编译器看不到,p==&s.z
?)
如果 2. 和 3. 的答案不同if constexpr
不存在,但我们知道(也许从编译器文档,或从以前的经验),没有填充S
?
如果 1. 是 UB(因此 2./3. 无意义),那么 2./3. 的答案是什么,如果p
是这样设置的(p
在数组的帮助下移动,但除此之外,片段是相同的)?
union U {
S s;
float a[3];
};
void fn() {
U u;
u.s.x = 0; u.s.y = 0; u.s.z = 0;
float *p = u.a; // here, p==&u.s.x as well
if constexpr(sizeof(S)==sizeof(float)*3) { // if S has no padding
p += 2;
float t = *p; // 2.
u.s.z = 1;
float z = *p; // 3.
}
}
陈述p += 2
其本身就是未定义的行为;p
是一个指向浮点对象的指针,它指向单个浮点对象(而不是指向这些对象的数组)。尽管就指针算术而言,单个对象被视为由一个元素组成的数组(例如,5.7 (4) https://timsong-cpp.github.io/cppwp/n3337/expr.add#4在线标准草案的一部分),将指针移到末尾两点。这个指针算术本身已经是 UB (cf.5.7 (5) https://timsong-cpp.github.io/cppwp/n3337/expr.add#5),无论您是否取消引用该指针。
请注意 - 即使您声明了三个连续的类型成员float
,即使编译器没有在其间引入填充,根据标准,第一个成员和完整的结构对象都不会成为数组。即使我们想到的内存布局可能与我们喜欢访问它的情况“兼容”,编译器也不会强制允许/翻译包含我们想到的任何意义上的 UB 的语句。
那么直接回答你的问题:
(1) 由于指针运算无效而为 UB
(2)由于访问无效指针而为UB
(3) 由于访问无效指针而导致 UB,因此任何关于编译器是否可以优化的问题都无法回答/没有意义。
关于union
-construct,在 C++ 中(与 C 不同),访问除先前编写的联合体成员之外的联合体成员又是 UB。所以写工会成员s
然后访问联盟成员a
再次导致 UB(尽管现在由于不同的原因)。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)