Pilcrow wrote:
....
Before posting my example I had already realised that I was not allowed
(at least in *this* case) to use a shortcut to modify an argument to a
function *within* the parens. I just assumed that the much-cited k&r
had fully defined the language. All these 'undefines' have me feeling
like I'm trying to herd cats. (snakes?)
K&R did not fully define the language. The C89 standard did define it,
but that definition included specifying, with considerable precision,
situations in which the standard does not specify the behavior.
Now I realise that I will have to read the 'standard', which seems to
have been written by a team composed of Philidelphia lawyers and
abstract mathematicians, neither of whom heard of Henry W Fowler. Truly
gelatinous prose. Technical writing need not be so murky. Oh, well, we
live to learn.
A key thing that you need to understand is that the standard is,
conceptually, a contract between implementors of C and developers of C
programs. If a developer writes strictly conforming code, a conforming
implementation has to produce exactly the behavior specified by the
standard. The "undefined behavior" that bothers you so much is simply
one of the several methods which the standard uses to identify code
which doesn't meet the contract requirements.
These ways are:
1. The standard requires that a conforming implementation must produce
at least one diagnostic message whenever given a program that contains
any syntax errors or constraint violations. An implementation is also
free to produce diagnostic messages for any other reason that it
wishes. Diagnostics are not required to provide you with any useful
information; they are not even required to be in any language that
anyone knows how to read. However, an implementation is required to
document how to identify diagnostic messages. If you don't find the
messages helpful, that's a legitimate issue to complain about to the
implementor - but it doesn't make the implementation non-conforming.
Having generated that diagnostic, an implementation is free to process
your code a produce a program that you might or might not be willing
to actually execute (I wouldn't).
2. Unspecified behavior: in some cases, the standard allows an
implementation a range of choices. This is usually not done just for
the fun of it - it's done because existing implementations handle the
situation in different ways, often because the best way to handle the
situation is different on different machines. By making the behavior
unspecified, the standard makes it easier to implement C in an
efficient fashion on a much wider variety of platforms than just about
any other language. The price we pay for this is that we have to be
careful to avoid writing code that depends upon unspecified behavior,
unless we have a very good reason to tie a program to a particular
implementation of C.
A program whose behavior is unspecified must still behave in one of
permitted ways, an implementation is not free to make it behave in a
completely arbitrary fashion. In many cases, unspecified behavior is
also implementation-defined behavior; in that case, the implementation
is required to document which choice it made. See Annex J.3 for
implementation-defined behavior; see Annex J.1 for other unspecified
behavior.
3. Undefined behavior: the standard imposes no requirements, of any
kind, on the behavior. An implementation is free to provide it's own
definition of the behavior. If you're deliberately relying upon a
particular implementation's definition of the behavior, that's fine.
However, if you intend your code to be portable, you must avoid
undefined behavior completely. See Annex J.2 for undefined behavior.
Maybe I'll try to make a catalog of *all* the 'undefines' and similar
gotchas in C. Written in English.
Virtually every sentence of the standard contains a "gotcha", many of
them contain several "gotchas". To write them out in clear English,
avoiding the technical jargon that makes the standard so difficult to
read, a complete list of the "gotchas" will have to be several times
longer than the standard itself.
....
BTW, what's a 'sequence point', and how could I recognize one in a dark
alley? Never mind, maybe the *standard* will tell me.
Here's the complete list of sequence points from Annex C: