I am facing confusion about the C++ strict-aliasing rule and its possible implications. Consider the following code:
int main() {
int32_t a = 5;
float* f = (float*)(&a);
*f = 1.0f;
int32_t b = a; // Probably not well-defined?
float g = *f; // What about this?
}
Looking at the C++ specs, section 3.10.10, technically none of the given code seems to violate the "aliasing-rules" given there:
If a program attempts to access the stored value of an object through an lvalue of other than one of the following types the behavior is undefined:
... a list of qualified accessor types ...
*f = 1.0f;
doesn't break the rules because there is no access to a stored value, i.e. I am just writing to memory through a pointer. I'm not reading from memory or trying to interpret a value here.- The line
int32_t b = a;
doesn't violate the rules because I am accessing through its original type. - The line
float g = *f;
doesn't break the rules for just the same reason.
In another thread, member CortAmmon actually makes the same point in a response, and adding that any possible undefined behavior arising through writes to alive objects, as in *f = 1.0f;
, would be accounted for by the standard's definition of "object lifetime" (which seem to be trivial for POD types).
HOWEVER: There is plenty of evidence on the internet that above code will produce UB on modern compilers. See here and here for example.
The argumentation in most cases is that the compiler is free to consider &a
and f
as not aliasing each other and therefore free to reschedule instructions.
The big question now is if such compiler behavior would actually be an "over-interpretation" of the standard.
The only time the standard talks about "aliasing" specifically is in a footnote to 3.10.10 where it makes clear that those are the rules that shall govern aliasing.
As I mentioned earlier, I do not see the any of the above code violating the standard, yet it would be believed illegal by a large number of people (and possibly compiler people).
I would really really appreciate some clarification here.
Small Update:
As member BenVoigt pointed out correctly, int32_t
may not align with float
on some platforms so the given code may be in violation of the "storage of sufficient alignment and size" rule. I would like to state that int32_t
was chosen intentionally to align with float
on most platforms and that the assumption for this question is that the types do indeed align.
Small Update #2:
As several members have pointed out, the line int32_t b = a;
is probably in violation of the standard, although not with absolute certainty. I agree with that standpoint and, not changing any aspect of the question, ask readers to exclude that line from my statement above that none of the code is in violation of the standard.
float
, because you never "obtained storage of sufficient size and correct alignment".a
is sized and aligned forint
, notfloat
, and some platforms will really let you know (to put it kindly). – Pilau