A89: C -- Boolean logic?


[Prev][Next][Index][Thread]

A89: C -- Boolean logic?




 > is there a way to do boolean logic in C?

Well, there is. Sorta.

By definition, in C (and in C++ and in Objective-C) relational operators
(==, !=, >, <, >=, <=) return an integer value, 0 for false and 1 for
true.

All decisive constructs ( if, while, for ) treat 0 as false and
*everything else* as true. 

if ( 2 ) { ... } is perfectly valid and is always taken. 

for ( n = 5 ; n ; n-- ) { ... } will start with n = 5 and loop around
until n becomes 0.

The ! operator is the logical negation: it makes 1 from 0 and 0 from
anything but 0.

Since comparisons return integer 1/0 values, normal bit-wise
operations can be used on them:

if ( ( a == 2 ) & ( ( b > 3 ) | ( c < 7 ) ) ) { .. }

will work.
The relevant operators are &, | and ^ for AND, OR and EXCLUSIVE-OR,
respectively. Note, however, that the bitwise negation operator, the
~ can *NOT* be used:

~0 = 0xffffffff which in the Boolean sense is true, correctly BUT
~1 = 0xfffffffe which in the Boolean sense is also true *incorrectly* !

Now there are 2 more operators which are *very* important in the
Boolean functionality of C. They are && and ||, logical AND and
logical OR, respectively.

They pretty much work as the & and | with two exceptions. The simpler
difference is that the && and || treat values as the if, for, while
constructs do, that is, 0 is false, anything else is true (note that
because of that they accept floating point values while the bitwise
operators do not). 

The more important difference is that they are only evaluated until
the final value of the logical expression can be decided. What that 
means is this:

if ( foo() == 3 && bar() == 4 ) { ...

First, the function foo() is called and the return value is compared
against 3. If it was 3, then bar() is called and depending on whether
it returned 4 or not the body of the if is executed or skipped.
However, if foo() did not return 3, then the value of the full logical 
expression is already known (false AND anything ==> false) therefore,
the other side of the && will *not* be evaluated, tha is, bar() will 
not be called. The same is true for the || :

if ( foo() == 3 || bar() == 4 ) { ...

if foo() returned 3, the expression is already known to be true
(true OR anything ==> true) therefore the right hand side won't be
evaluated and bar() will not be called.

With the additional knowledge that 

- both operators have a left to right evaluational order (most C
  operators have *no* guaranteed evaluation order), and
  
- both operators are right associative

one can use them to build complex nested if - else if chains without
ever typing if or else.

One more operator is worth to mention because it is quite unusual and
very, very useful. It is the ?: operator of C.
If you have a function foo and depending on whether a function bar()
returns 5 or not, you want to pass 3 or the content of the variable baz 
to foo. In both case the return value of foo() should be stored in
the variable called result. That is:

if ( bar() == 5 )

   result = foo( 3 );
else
   result = foo( baz );
   
Now the <exp1> ? <exp2> : <exp3> construct will evaluate <exp1> and if 
it is true, then it will evaluate <exp2> and assume its value. If
<exp1> evaluated to false, then <exp3> is evaluated and its value
becomes the value of the construct. That is, the above example could 
be written as:

   result = foo( bar() == 5 ? 3 : baz );
   
Note that it is very different from an if construct. You can not use
an if in an expression but you can use this. 
This construct also guarantees an evaluation order (<exp1> first,
<exp2> or <exp3> next but only one of them).

As usual, let me point out that if you are going to do serious C
programming, try to get the K&R book (ISBN 0-13-110362-8).

Regards,

Zoltan


Follow-Ups: References: