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.,p
is moved two elements beyond froms.x
, so it points beyond&s.x+1
) - Here, we know that
S
doesn't have padding, isfloat t = *p;
UB? Or is it well defined, thatt
should contain the value ofs.z
? - Can an optimizer optimize access to
p
atfloat z = *p;
? I mean, is it allowed toz
be 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.
}
}