The C language does not have a Boolean datatype, using integers instead. Comparison operators such as == and <= return the integer value 0 for false and 1 for true. However, the if statement in C considers any nonzero value of its condition to be equivalent to true. Why the difference? Why not allow the relational operators to return any nonzero value to represent true?
4 Answers
I believe it was an arbitrary decision, going back to C's ancestor language B.
Quoting the Users' Reference to B:
The relational operators
<(less than),<=(less than or equal to),>(greater than), and>=(greater than or equal to) take integer rvalue operands. The result is one if the operands are in the given relation to one another. The result is zero otherwise.
No explanation is given of this particular choice, nor is it explained in the ANSI C Rationale or in the 1978 1st edition of Kernighan & Ritchie's book "The C Programming Language" (K&R1).
(B's ancestor language BCPL had true and false literals, with true being represented with all bits set to 1.)
The language could have been defined differently, and it still would have been internally consistent. For example, the standard could have said that the relational and equality operators yield a result of 0 if the condition is false, or any arbitrary non-zero value if the condition is true. The result could still be used correctly in an if statement, or any other context requiring a condition. And it's easy to imagine a CPU on which it's more efficient for a true value to be represented as all-bits-one rather than as 1 -- but the language standard doesn't permit that.
Several standard library functions, such as isdigit(), may return any arbitrary non-zero value to indicate a true condition, which further demonstrates that this was an arbitrary choice. (isdigit is naturally implemented via a table lookup which can yield values other than 0 and 1).
There is some added convenience in having the equality and relational operators yield 0 and 1. For example, this makes it easy to keep a count of how many conditions are true:
int count = 0;
count += x == y;
count += foo > bar;
count += this <= that;
My guess is that it was convenient to use 0 and 1 in the first B compiler, the behavior was documented, and it's been inherited up until today. Changing the definition would have broken code that depended on the previous definition.
And even if it's relatively inefficient on some systems, it's not a huge problem. The result of an equality or relational operator is not usually stored anywhere, so a compiler can represent the result however it likes as long as the behavior is consistent. It might have to generate code to normalize the result to 0 or 1 in some cases, but that's not likely to be significant.
Comments
If a conditional expression could return any nonzero value for true, you could get into trouble when storing it into too small variable, in the extreme case a one-bit bitfield.
struct foo { unsigned int bar: 1; } baz;
baz.bar = 1 == 1;
If the 1 == 1 conditional returned 2 (or any even number), you'de be in trouble as baz.bar would end up 0, which evaluates as false in a boolean context.
Comments
When you use a relational operator inside a conditional, the compiler is going to compile it into a "jump if greater" or similar operator and wont bother actually computing the return value of the <= expression. It doesn't matter that the expression always return 0 or 1 because that value is never actually computed.
The only time where relational operators returning 0 or 1 will matter is when their value is used in a larger expression, like arithmetic or assigning to a variable. This is much less common than the situation of directly using them in a branch and the convenience of always returning 1 is not very costly.
2 Comments
< is not equivalent to subtraction. Suppose x==INT_MAX and y==INT_MIN.In C, 0 is false whether it's the return type from a comparison operator or an if statement, or whatever you want to check. However, while the if() statement will accept anything for true that isn't zero, the comparison operators must return only one object, and so it was decided that that object would be '1'. It's the difference between whether you're returning or accepting.
Just like in any other function, say int foo(int x){} you can accept any value of x, but you have to actually choose, before you leave the function, what you want to return. I suppose you could return a random number, but what good would that do? '1' was chosen instead.
10 Comments
strcmp() return any negative or positive value when strings are different? :)strcmp() returns a negative, 0, or positive value. It needn't be the difference between anything -- though that's sometimes a convenient way to implement it.
0and1, the language permits "shorthand calculations":n += (n % 2 == 0); // increment n if it is even; Also the language already takes any nonzero value to represent true: just use it directly in conditions without relational operators._Bool/bool, defined instdbool.h._Bool(aliased asboolif you have#include <stdbool.h>). It was added by the 1999 ISO C standard. But the comparison operators still yieldintresults.