Look at this snippet:
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.
}
}
My questions are:
- Is
p += 2;UB? (i.e.,pis moved two elements beyond froms.x, so it points beyond&s.x+1) - Here, we know that
Sdoesn't have padding, isfloat t = *p;UB? Or is it well defined, thattshould contain the value ofs.z? - Can an optimizer optimize access to
patfloat z = *p;? I mean, is it allowed tozbe 0? (is it allowed for a compiler to fail to see, thatp==&s.z?)
Does the answer differ for 2. and 3., if the if constexpr is not there, but we know (maybe from the compiler documentation, or from previous experience), that there is no padding in S?
If 1. is UB (so 2./3. meaningless), then what's the answer to 2./3., if p is set like this (p is moved with the help of an array, but otherwise, the snippet is the same)?
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.
}
}