• Have you noticed that the conditions we’ve used so far
have been very simple, not to say – quite primitive? The conditions we use in real life are much more complex. Let's look at the sentence: If we have some free time, and the weather is good, we will go for a walk. We’ve used the conjunction “and”, which means that going for a walk depends on the simultaneous fulfillment of the two conditions. In the language of logic, the connection of conditions is called a conjunction. And now another example: If you are in the mall or I am in the mall, one of us will buy a gift for Mom. The appearance of the word “or” means that the purchase depends on at least one of these conditions. In logic terms, this is called a disjunction. Therefore, the “C” language must have operators to build conjunctions and disjunctions. Without them, the expressive power of the language would be substantially weakened. We call these logical operators. • The logical conjunction operator in the “C” language is a digraph && (ampersand ampersand).
This is a binary operator with a
priority lower than the comparison operators. It allows us to code complex conditions without the use of parentheses like this one → Pride && Prejudice • The result provided by the && operator can be determined on the basis of the truth table. If we consider the conjunction of: left && right the set of possible values of arguments and corresponding values of the conjunction looks as follows → To be || not to be • The disjunction operator is the digraph | | (bar bar). It’s a binary operator with a lower priority than && (just like “+” compared to “*”). Its truth table looks as follows → To be || not to be • In addition, there’s another operator that can be used to construct conditions. It’s a unary operator performing a logical negation. Its operation is simple: it turns true into false and false into true. This operator is written as a single character ! (exclamation mark) and its priority is very high: the same as the increment and decrement operators. • Its truth table is truly simple → Some logical expressions • Note that the following conditions are equivalent, respectively → Some logical expressions • You may remember De Morgan's laws from school. They say that: The negation of a conjunction is the disjunction of the negations. The negation of a disjunction is the conjunction of the negations. • Let's try to write the same thing using the “C” language → Note how the parentheses have been used to code the expressions. We should add that none of the previous two- argument operators can be used in the abbreviated form known as op=. This exception is worth remembering. How to deal with single bits • Logical operators take their arguments as a whole, regardless of how many bits they contain. The operators are aware only of the value: 0 (when all the bits are reset) means “false”; not 0 (when at least one bit is set) means “true”. The result of their operations is one of the values: 0 or 1. This means that the following snippet will assign a value of 1 to the j variable if i is not zero; otherwise, it will be 0 (why?). However, there are four operators that allow you to manipulate single bits of data. We call them bitwise operators. They cover all the operations we mentioned before in the logical context and one additional operator. This is the xor (exclusive or) and is denoted as ^ (caret). Here are all of them: & (ampersand) bitwise conjunction | (bar) bitwise disjunction ~ (tilde) bitwise negation ^ (caret) bitwise exclusive or Let's make it easier: & requires exactly two “1s” to provide “1” as the result | requires at least one “1” to provide “1” as the result ^ requires only one “1” to provide “1” as the result ~ (is one argument and) requires “0” to provide “1” as the result But take note: arguments of these operators must be integers (int as well as long, short or char); we must not use floats here. The difference in the operation of the logical and bit operators is important: the logical operators do not penetrate into the bit level of its argument. They’re only interested in the final integer value. Bitwise operators are stricter: they deal with every bit separately. If we assume that the int variable occupies 32 bits, you can imagine the bitwise operation as a 32-fold evaluation of the logical operator for each pair of bits of the arguments. Obviously, this analogy is somewhat imperfect, as in the real world all these 32 operations are performed at the same time. How to deal with single bits • Let’s have a look at an example of the difference in operation between logical and bit operations. Let’s assume that the following declaration has been performed: • int i = 15, j = 22; • If we assume that the ints are stored with 32 bits, the bitwise image of the two variables will be as follows → How to deal with single bits • The declaration is given:
int log = i && j;
We’re dealing with a logical conjunction. Let’s
trace the course of the calculations. Both variables i and j are not zeros so will be deemed to represent “true”. • If we look at the truth table for the && operator, we can see that the result will be “true” and that it’s an integer equal to 1. This means that the bitwise image of the log variable is as follows → • Now the bitwise operation – here it is:
int bit = i & j;
The & operator will operate with each pair of
corresponding bits separately, producing the values of the relevant bits of the result. Therefore, the result will be as follows →
These bits correspond to an integer value of 6.
How to deal with single bits • Let's try the negation operators now. First the logical one:
int logneg = !i;
The logneg variable will be set to 0 so its image will consist of
zeros only. The bitwise negation goes here:
int bitneg = ~i;
It may be somewhat surprising that the bitneg variable value is
-16. Strange? Not at all! If you’re surprised, we hope it’ll be an incentive for you to immerse yourself in the secrets of the binary numeral system and the rules governing two's complement numbers. • Each of the previous two- argument operators can be used in their abbreviated forms. The following notations are equivalent, respec vely →