Looking at the C code from the Fast Inverse Square Root, the casting of a float to a long is done via pointer arithmetic:
i = * ( long * ) &y; // evil floating point bit level hacking
The hacking in question isn't of immediate interest to me. The method, using pointer arithmetic to access the memory values of one type and assign them to another is where my question lies. Later in the article they note that this behavior is now proscribed in the C standard, but which standard is not specified.
We can see from this StackOverflow answer that in C++, "dereferencing a pointer that aliases an object that is not of a compatible type or one of the other types allowed by C 2011 6.5 paragraph 7 is undefined behavior." (internal footnotes and links omitted) That's C++, but this answer (on the same issue, the strict aliasing rule) in C notes that a way around the problem of producing undefined behavior appeared with unions in C99.
From K&R C (2nd edition), page 103 we have:
“The valid pointer operations are assignments of pointers to the same time, adding or subtracting a pointer and an integer, subtracting or comparing two pointers to members of the same array, and assigning or comparing to zero. All other pointer arithmetic is illegal. It is not legal to add two pointers, or to multiple or divide or shift or mask them, or to add
float
ordouble
to them, or even, except forvoid*
, to assign a pointer of one type to a pointer of another type without a cast.”
This seems pretty explicitly to disallow the trick above. However I don't know what force this statement had in terms of code in the wild. Worth noting that Ritchie, writing in 1993, remarks "Compilers in 1977, and even well after, did not complain about usages such as assigning between integers and pointers or using objects of the wrong type to refer to structure members. Although the language definition presented in the first edition of K&R was reasonably (though not completely) coherent in its treatment of type rules, that book admitted that existing compilers didn't enforce them."
I recognize that this behavior has always been undefined. What I am trying to figure out is when and where is became specifically disallowed, meaning:
- When did we start modifying compilers to emit errors or warnings for this behavior? GCC will still compile the Quake FISR with arguments
-O0
- Was this behavior identified in the c99 standard? in the c90 standard?
- Apart from reading the standard, how might a C programmer learn that this was behavior to be avoided and not the good kind of cleverness? K&R C strikes me as a good example, are there others?
That's three sub-questions, so I apologize for that. I'm looking for information on this pattern and so any help will be useful.