George Neuner <
gneuner2@comcast.net> writes:
I'm not going to argue about whether UB in code is wrong. The
question I have concerns what to do with something that explicitly
is mentioned as UB in some standard N, but was not addressed in
previous standards.
>
Was it always UB? Or should it be considered ID until it became
UB?
>
It does seem to me that as the C standard evolved, and as more
things have *explicitly* become documented as UB, compiler
developers have responded largely by dropping whatever the
compiler did previously - sometimes breaking code that relied on
it.
For the most part the circumstances you describe simply don't
occur. I know of one case where a rule introduced in C11
identified a specific situation as undefined behavior whereas
in C99 and before it was arguably not undefined behavior (but
never behavior that should be relied on). I don't remember
any others; if you have any specific examples please mention
them.
Something that does happen is a rule is given fuzzily in one
version of the C standard and then made more precise in a later
version. A good example of that is evaluation sequencing.
Before C11 the rules about what evaluations must be done before
other evaluations were not as clear as they should be. C11 fixed
that. However in that case I don't think anything went from
certainly defined (or certainly unspecified) to undefined, but
rather changed in the other direction, from possibly undefined
to certainly defined. Offhand I don't remember any other
examples, although surely there must be some.
Sometimes it happens that there is a change in the C language not
because wording in the Standard changes but because how the
wording in the Standard is interpreted, usually through a
response to a Defect Report. A good example of this kind of
change is "wobbly bits" - the idea that when a variable has not
been initialized then the bits of the variable are allowed to
change at any time. (By the way, IMO this idea is completely
stupid.) As far as I am aware this principle is not stated
anywhere in the C standard itself, but has crept into how the C
standard is interpreted by way of responses to Defect Reports.
It could be that changes of this kind is what you are thinking
about.
Overall though, I think the greatest changes in compiler behavior
are a result not of changes in the C standard but of optimization
techniques becoming more aggressive. To make things worse, it
isn't always clear whether a changed behavior is the result of a
more aggressive advantage-taking of a true UB situation, or if
the optimizer is buggy. I encountered an interesting situation
recently where a given piece of code worked just fine under both
gcc and clang, *except* under gcc at level O3 (clang at O3 had no
problems). It's been more than a decade since C11 was ratified
(and nearly a quarter of a century since C99). Compilations
should always be done with an explicit -std=c99 or -std=c11. If
you have been compiling with -std=c99 all this time, or even
using -std=c11 over the shorter time frame, and you see changes
between different versions of the compiler, it's not the C
standard changing that's causing the problem, but how the
compiler is choosing to act on what should be a fixed set of
rules.
Completely coincidentally, I happened to see a couple of
videos recently
https://www.youtube.com/watch?v=si9iqF5uTFk Grace M Hopper I
https://www.youtube.com/watch?v=AW7ZHpKuqZg Grace M Hopper II
that I think folks in comp.arch might be interested to watch.
The second one deals with language versions and compiler
verification (among other topics). A bit on the long side
but I enjoyed watching them.