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.