12.1 Varieties of Unportability
Autoconf tests and ordinary programs often need to test what is allowed
on a system, and therefore they may need to deliberately exceed the
boundaries of what the standards allow, if only to see whether an
optional feature is present. When you write such a program, you should
keep in mind the difference between constraints, unspecified behavior,
and undefined behavior.
In C, a constraint is a rule that the compiler must enforce. An
example constraint is that C programs must not declare a bit-field with
negative width. Tests can therefore reliably assume that programs with
negative-width bit-fields are rejected by a compiler that conforms
to the standard.
Unspecified behavior is valid behavior, where the standard allows
multiple possibilities. For example, the order of evaluation of
function arguments is unspecified. Some unspecified behavior is
implementation-defined, i.e., documented by the implementation,
but since Autoconf tests cannot read the documentation they cannot
distinguish between implementation-defined and other unspecified
behavior. It is common for Autoconf tests to probe implementations to
determine otherwise-unspecified behavior.
Undefined behavior is invalid behavior, where the standard allows
the implementation to do anything it pleases. For example,
dereferencing a null pointer leads to undefined behavior. If possible,
test programs should avoid undefined behavior, since a program with
undefined behavior might succeed on a test that should fail.
The above rules apply to programs that are intended to conform to the
standard. However, strictly-conforming programs are quite rare, since
the standards are so limiting. A major goal of Autoconf is to support
programs that use implementation features not described by the standard,
and it is fairly common for test programs to violate the above rules, if
the programs work well enough in practice.