Control Flow & Bitwise

Comparison Operators & The Boolean Type

In order to have our code behave differently depending on the conditions during runtime, we need to be able to represent and answer “yes no” questions in our code.

Some of the questions that we might ask are, for example:

To compare values, we can use comparison operators, like so:

Yet we still need a way to store the answer to these questions (the results of these expressions). Thus we have another data type called the “boolean” type in C.

Booleans can only have two values: true (1) or false (0).

To declare a boolean variable, we use the bool keyword.

(Note: We also need to do #include <stdbool.h> to enable bool type in C.)

int a = 4, b = 7;
bool x;
x = (a < b);  // x has value **true**
x = (a >= b);  // x now has value **false**

// Important Note: Boolean values are also represented with integers,
// where true is 1 and false is 0.
int x; 
x = (a < b);  // x has value 1
****x = (a >= b);  // x now has value 0

Comparison operators have lower priority than arithmetic operators, for example:

For the expression x == 2 * y, “2 * y” is evaluated first, then == is evaluated.

Our now updated operator precedence table would be:

+, -, ++, – (unary operator)
*, /, %  
+, - (binary operator)
<, <=, >, >= (comparison)
==, != (comparison)
=, +=, -=, *=, /=, %= (assignments)

Conditional Execution

C has special instructions that allow us to execute code only upon certain conditions. These instructions are called conditional instructions or conditional statements.

Simple If Statement

The simple if statement takes the form:

if(bool_expression){
    ...  // Do this if bool_expression evaluates to true.
}

// If bool_expression is false, then the instructions inside the parentheses
// will be skipped.

We can put many instructions inside the brackets, and if bool_expression is true, then the instructions inside will be conditionally executed. These instructions are called a compound statement or a block, and they are seen as 1 statement by the compiler.

If we have multiple instructions inside an if statement, they must be indented by 1 level from the code outside the brackets, like so:

if(x > y){
    x = x + y;
    y = y + x;
}
x = y;

This style of writing code is called the K & R Style, named after the creators of C.

Note that we can also omit the brackets whenever there’s only one statement inside the if statement, like so:

if(bool_expression)
    doSomething();

If-Else Statement

The if ... else statement takes the form:

if(bool_expression){
    ...  // Do this IF AND ONLY IF bool_expression is true.
}else{
    ...  // Do this IF AND ONLY IF bool_expression is false.
}

Note that we can also nest if statements inside of if statements, this is called nesting. For example:

if(condition){
    if(another_condition){
        ...
		}
}else{
    if(a_third_condition){
        ...
    }else{
        ...
    }
}

Else If

The else if statement is a bit complex, it takes the form:

if(first_condition){
    ... // Do this if first_condition is true, then SKIP all remaining conditions.
}else if(second_condition){
    ... // Do this if first_condition is false, but second_condition is true.
}else if(third_condition){
    ... // Do this if both conditions above are false, but third_condition is true.
}

We can also add a condition to handle the case when all conditions are false, like so:

if(first_condition){
    ...
}else if(second_condition){
    ...
}else if(third_condition){
    ...
}else{
    ... // Do this when ALL conditions above are false.
}

Note that the program will examine the conditions sequentially. Whenever a condition is met, the corresponding code block will be run, and afterwards the rest of the conditions will be skipped.

So say for example if first_condition and third_condition are both true, then only the block corresponding to first_condition will be run, and the block corresponding to third_condition will be skipped.

Boolean Logic

Bitwise Operations

Bitwise operations treat values (integer values like int, short, char) as arrays of binary digits (e.g. short x = 126; would be 00000000 11111110), and then do logical operations on them bit by bit.

Bit Shifting

Bit shifting treat values (integer values like int, short, char) as arrays of binary digits (e.g. short x = 126; would be 00000000 11111110), and then shift the bits either left or right.

Thus the up-to-date operator precedence table would be:

!, ~, (typecast), +, -, ++, – (unary operators)  
*, /, % (binary arithmetic - high priority)  
+, - (binary arithmetic - low priority)  
«, » (bit shift operators)  
<, <=, >, >= (comparison operators - high priority)  
==, != (comparison operators - low priority)  
& bitwise AND  
| bitwise OR  
&& logical AND  
|| logical OR  
=, +=, -=, *=, /=, %=, &=, ^=, =, «=, »= (assignments and shorthands)

Switch-Case

A switch … case statement takes the form:

switch(expression){
    case LITERAL_1:
        ...  // Runs if expression == LITERAL_1
        break;  // After running, skip to the end
    case LITERAL_2:
				...  // Runs if expression == LITERAL_2
				break;  // skip to end

		case LITERAL_3:
				...  // Runs only when expression is LITERAL_3
		case LITERAL_4:
				...  // Runs when expression is LITERAL_3 or LITERAL_4,
				     // since there's not break statement at the end of LITERAL_3's case
				break;

		default:
				...  // Runs if expression is not equal to any of the above literals.

}

Each of the cases are scanned sequentially, just like in if ... else if statements.

Note that unlike if ... else if statements, after running instructions inside a case, the program does not skip to the end, and keeps on running, unless there’s a break; statement at the end of a case block.