Is it certain that ( a<b && b<c && !(a<c) ) is 0?
No.
First assume that each of a b c is a constant
per ISO/IEC 9899:1999 6.4.4 ?
None of the counterexamples that I was able to come up with could be
demonstrated using constants, since C constants cannot be negative (-1
is a unary expression, not a constant), or have pointer type, be NaNs,
or have a trap representation.
If not, what about a counterexample?
For pointer types the behavior is undefined unless all three pointers
point into or one past the end of the same array object.
Any relation involving a NaN is required to have a value of false.
#include <math.h>
double a = 1.0;
double b = nan();
double c = 2.0;
Another type of counter-example involves expressions where the usual
arithmetic conversions (6.3.1.8p1) result in the same variable being
converted to two different values in the two different places where it
occur in that expression:
unsigned long a = 98765UL;
int b = -12345;
short c = 1;
The key here is that in a<b, unsigned long has greater rank than long.
As a result, the usual arithmetic conversions (6.3.1.8p1) call for b to
be converted to unsigned long, with the resulting value of
ULLONG_MAX-12344, which is guaranteed to be greater than 98765UL. The
same conversion occurs in a<c, but since c is positive, the conversion
doesn't change it's value. No such conversion occurs in b<c.
How far can we extend (or shrink) the kind of things
that a b c can be for this to hold?
In particular, what about unitialized variable such as
int foo(void) {
{
unsigned a,b,c;
return a<b && b<c && !(a<c);
An uninitialized object may contain a trap representation. If that's the
case, attempting to read it will render the behavior undefined. When the
behavior is undefined, then anything is permitted by the standard. foo()
could return 1, or 0, or -3.5, or "You did it wrong". Your program could
also abort(), or get stuck in an infinite loop, or send hate mail to
your boss.
}
What if unsigned is changed to int? To double?
The behavior of foo() may be undefined when using any type which is
allowed to have a trap representation. The types which are not allowed
to trap include char, unsigned char, signed char, and the exact-width
types from <stdint.h>.
However, even if you use only those types for a, b, and c, the value you
get by reading an uninitialized variable is unspecified; it's not
required to be the same unspecified value each time you read it.
Therefore, foo() could still return either 0 or 1.