Richard said:
Where does "undefined" in any shape or form indicate that there will be
knock on effects outside of the value of the variable in question
considering it is not used anymore? And if that variable is not used
anymore does it really matter? Its like using (or not using rather) an
uninitialised pointer.
Yes, I know "undefined" can mean "anything", but lets stay real here for
a moment. Possibly "undefined" is "defined" to mean "undefined for that
variable in question".
Or?
Or, it means that the compiler is allowed to perform optimizations
elsewhere in your program, based upon the assumption that your code does
not have undefined behavior.
Specifically, your use of 'p--' at that point in the program can be used
by the compiler as an indication that p does NOT point at the start of
the array. As a result, if there is a previous statement that uses 'p',
and the compiler can verify that the value of 'p' should not be changed
between that previous statement and the entry to your while() loop, then
the compiler is free to optimize that previous use of 'p', by making
that same assumption.
For example, if that previous statement were
q = (p+3)-1;
the compiler would be free to rearrange that as
q = (p-1)+3;
Now, I'm not claiming that this is actually an optimization. There's no
obvious benefit to that rearrangement, it's just the simplest example I
could think of, of a legal rearrangement with potentially fatal
consequences. The point is, that because you use 'p--' later on in the
code, the compiler is free to investigate such rearrangements at this
earlier point in the code. If it finds a rearrangement that it prefers
over the original code, it is permitted to use it.
This is true even if the compiler is compiling for a platform where
calculating p-1 would abort the program if p happens to point at the
beginning of a memory segment. The original version of the code is
carefully written to avoid that problem, but because of the later use of
'p--', the compiler is allowed to rearrange it on the assumption that
p-1 has defined behavior. If p-1 and p+3 both have defined behavior,
then the behavior of (p+3)-1 and (p-1)+3 are both guaranteed to be
identical to p+2.
This is an example of why it's a mistake to assume that the consequences
of writing a code construct with undefined behavior are restricted to
the execution of that particular code construct. This is why the
standard standard specifies that it is the behavior of your ENTIRE
program that is undefined, not just the behavior of the particular
construct that makes it undefined.
And yes, this is a "real world" issue; modern compiler technology does
include the ability to perform optimizations at locations in the code
that are far away from the site of the code construct that gives them
permission to perform the optimization.